I am working on adding an AuthGuard to my Ionic 4 project. The guard checks if the user is logged in, if true the user continues to the home page, if false the user is redirected to the login page. The problem is when the user is redirected to the login page because of the guard the Angular Material label does not work correct. When the login page is visited without involving the guard everything works correctly.
AuthGuard service:
import { Injectable } from '#angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot } from '#angular/router';
import { UserService } from './user.service';
import { AngularFireAuth } from '#angular/fire/auth';
import { auth } from 'firebase/app';
#Injectable({
providedIn: 'root'
})
export class AuthService implements CanActivate {
constructor(
private router: Router,
public afAuth: AngularFireAuth,
private user: UserService) {
}
canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
return new Promise((resolve, reject) => {
this.afAuth.auth.onAuthStateChanged(user => {
if (user) {
// User is signed in.
resolve(true);
} else {
// No user is signed in.
resolve(false);
this.router.navigate(['login']);
}
});
});
}
}
login.page.html
<ion-content>
<div class="blue-background">
<img src="assets/logo.png" width="33%" height="18.6%" style="display: block; margin-left: auto; margin-right: auto;"/>
</div>
<div class="form_wrapper">
<div class="form_container">
<div class="row clearfix">
<div class="">
<mat-form-field appearance="outline" style="height: 40px; margin-bottom: 1.5em;">
<mat-label>Email</mat-label>
<input matInput style="min-height: 40px;" type="email" [(ngModel)]="username">
</mat-form-field>
<mat-form-field appearance="outline" style="height: 40px; margin-bottom: 1.5em;">
<mat-label>Password</mat-label>
<input matInput style="min-height: 40px;" type="password" [(ngModel)]="password">
</mat-form-field>
<ion-button style="margin-top: 10px; float: right; overflow: auto" fill="clear" size="small" color="dark" (click)="goToForgotPassword()">Forgot password?</ion-button>
<ion-button style="clear: both; overflow: auto" fill="solid" expand="block" color="dark" (click)="login()">Login</ion-button>
</div>
</div>
</div>
</div>
</ion-content>
Image of how the fields should work.
Image of how the fields work after the AuthGuard redirect. Notice the labels don't float.
Related
I have to create a book appraisal market where students can enter their book's data (title, ISBN, version, price). If the data is entered correctly, display data in another tab called 'View Appraisals'. Now, I have made this tab and everything works fine, but I have to add one more feature that would display the View Appraisals tab on all pages' tab, in the tab bar, once the user entered the correct data.
I will be adding all my code to create the program.
Model:
namespace Lab4_Students4CheapTexts.Models
{
public class Textbooks
{
// declaring data members and getter/setter
[Required]
[StringLength(100)]
public string title { get; set; }
public int ISBN { get; set; }
public int version { get; set; }
[Required]
public int price { get; set; }
// no parameter constructor
public Textbooks()
{
}
// full parameter constructor
public Textbooks(string title, int ISBN, int version, int price)
{
this.title = title;
this.ISBN = ISBN;
this.version = version;
this.price = price;
}
public override string ToString()
{
return "Your textbook: " + this.title + ", version: " + this.version + " was appraised at: " + this.price;
}
}
}
Controller:
public class HomeController : Controller
{
List<Textbooks> textbooksList = new List<Textbooks>();
public IActionResult Index()
{
return View();
}
[HttpGet]
public IActionResult Appraise()
{
return View();
}
[HttpPost]
public IActionResult Appraise(Textbooks textbooks)
{
if (ModelState.IsValid)
{
ViewData["Message"] = "Your textbook: " +
textbooks.title +
", Version: " +
textbooks.version +
" was priced at: " +
textbooks.price;
return View("view_appraisals", textbooks);
}
else
{
return View("Bad");
}
}
}
}
Views:
INDEX.CSHTML
<article id="box">
<header>
<h1>Students4CheapTexts</h1>
<img src="~/Images/logo.png"
alt="Logo"
height="50"
width="50" />
</header>
<ul>
<li><a class="active" href=".~/Home/Index">Home</a></li>
<li>Appraise</li>
</ul>
<p>
index
</p>
</article>
APPRAISE.CSHTML
<ul>
<li>Home</li>
<li><a class="active" href="~/Home/Appraise">Appraise</a></li>
</ul>
<form action="~/Home/Appraise" method="POST">
<div>
<label for="title">Textbook Title:</label>
<input type="text" id="make" name="title" placeholder="" />
<br />
</div>
<div>
<label for="isbn">Textbook ISBN:</label>
<input type="text" id="isbn" name="isbn" placeholder="" />
<br />
</div>
<div>
<label for="version">Textbook Version:</label>
<input type="text" id="version" name="version" placeholder="" />
<br />
</div>
<div>
<label for="originalPrice">Original Purchase Price:</label>
<input type="text"
id="originalPrice"
name="originalPrice"
placeholder="" />
<br />
</div>
<div>
<label for="condition">Condition:</label>
<select name="condition" id="condition">
<option value="likeNew">Like New</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
</select>
<br />
</div>
<input type="submit" value="Appraise" />
</form>
VIEW_APPRAISALS.CSHTML
<header>
<h1>All Entered Books List</h1>
<img src="~/Images/logo.png" alt="Logo" height="50" width="50" />
</header>
<ul>
<li>Home</li>
<li>Appraise</li>
<li><a class="active" href="~/Home/view_appraisals">View Appraisals</a></li>
</ul>
<h3> The model car could not be created because you have entered something incorrectly.</h3>
BAD.CSHTML
<header>
<h1>Incorrect input</h1>
<img src="~/Images/logo.png" alt="Logo" height="50" width="50" />
</header>
<ul>
<li>Home</li>
<li>Appraise</li>
</ul>
<h3> The model car could not be created because you have entered something incorrectly.</h3>
CSS for all my HTML pages:
/* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */
a.navbar-brand {
white-space: normal;
text-align: center;
word-break: break-all;
}
/* Provide sufficient contrast against white background */
a {
color: #0366d6;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.nav-pills .nav-link.active,
.nav-pills .show > .nav-link {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
/* Sticky footer styles
-------------------------------------------------- */
html {
font-size: 14px;
}
#media (min-width: 768px) {
html {
font-size: 16px;
}
}
.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}
.box-shadow {
box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.05);
}
button.accept-policy {
font-size: 1rem;
line-height: inherit;
}
/* Sticky footer styles
-------------------------------------------------- */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
outline: none;
}
html {
position: relative;
min-height: 100%;
font-family: sans-serif;
}
body {
/* Margin bottom by footer height */
margin: 60px;
text-align: center;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px; /* Vertically center the text there */
}
ul {
display: inline-block;
margin: 20px;
padding: 20px 0;
background: #aaa;
border: 1px solid #000;
}
ul li {
display: inline-block;
}
ul li a {
text-decoration: none;
color: #000;
padding: 20px 30px;
font-size: large;
font-weight: bold;
}
ul li a.active {
background: #eee;
}
p {
width: 40vw;
text-align: justify;
margin: auto;
line-height: 35px;
}
article.box {
background-color: #ddd;
}
form {
border: 1px dotted #000;
width: 60vw;
padding: 20px 0;
margin: auto;
}
form div {
margin: 20px 0;
}
form div input {
border: 1px solid #000;
}
form input[type=submit] {
padding: 10px 20px;
}
header h1 {
font-size: 40px;
}
You can perhaps put the Partial Tag Helper on each of the cshtml pages you want to include in any of your tabs.
Index.cshtml
<article id="box">
<header>
<h1>Students4CheapTexts</h1>
<img src="~/Images/logo.png"
alt="Logo"
height="50"
width="50" />
</header>
<ul>
<li><a class="active" href=".~/Home/Index">Home</a></li>
<li>Appraise</li>
</ul>
<p>
Here is stuff from indes page and below is the stuff from View_Appraisals. You can include it anywhere.
<hr />
<partial name="VIEW_APPRAISALS">
</p>
If the data is entered correctly, display data in another tab called
'View Appraisals'. Now, I have made this tab and everything works
fine, but I have to add one more feature that would display the View
Appraisals tab on all pages' tab, in the tab bar, once the user
entered the correct data.
You could try to use the _layout page to display the tab bar navigation link, code like this:
_layout.cshtml: (check the navbar)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>#ViewData["Title"] - WebApplication1</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">WebApplication1</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" href="~/Home/Appraise">Appraise</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" href ="~/Home/view_appraisals">View Appraisals</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
#RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2020 - WebApplication1 - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
#await RenderSectionAsync("Scripts", required: false)
</body>
</html>
Then, in other views, there is no need to add navigation link, just using the layout page, code like this:
Index.cshtml:
#{
ViewData["Title"] = "Home Page";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<article id="box">
<p>
index Page
</p>
</article>
Code in the Appraise.cshtml page:
<h1>Appraise</h1>
#*<ul>
<li>Home</li>
<li><a class="active" href="~/Home/Appraise">Appraise</a></li>
</ul>*#
<form action="~/Home/Appraise" method="POST">
<div>
<label for="title">Textbook Title:</label>
<input type="text" id="make" name="title" placeholder="" />
<br />
</div>
<div>
<label for="isbn">Textbook ISBN:</label>
<input type="text" id="isbn" name="isbn" placeholder="" />
<br />
</div>
<div>
<label for="version">Textbook Version:</label>
<input type="text" id="version" name="version" placeholder="" />
<br />
</div>
<div>
<label for="originalPrice">Original Purchase Price:</label>
<input type="text"
id="originalPrice"
name="originalPrice"
placeholder="" />
<br />
</div>
<div>
<label for="condition">Condition:</label>
<select name="condition" id="condition">
<option value="likeNew">Like New</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
</select>
<br />
</div>
<input type="submit" value="Appraise" />
</form>
Code in the view_appraisals view:
#model IEnumerable<WebApplication1.Models.Textbooks>
<table class="table">
#* list all model *#
</table>
In the controller, I will use the session to store the correct data. After submitting the correct data, store the data into session, then, get data from the session and display all the records. You could also store them into the database. (To use session in asp.net core, check Session and state management in ASP.NET Core, then configure session state and add the SessionExtensions (uses to store complex object)).
public IActionResult Index()
{
return View();
}
[HttpGet]
public IActionResult Appraise()
{
return View();
}
[HttpPost]
public IActionResult Appraise(Textbooks textbooks)
{
if (ModelState.IsValid)
{
ViewData["Message"] = "Your textbook: " +
textbooks.title +
", Version: " +
textbooks.version +
" was priced at: " +
textbooks.price;
//check if session exist and the the data.
if (HttpContext.Session.Get<List<Textbooks>>("textbooks") != null)
{
textbooksList = HttpContext.Session.Get<List<Textbooks>>("textbooks");
}
textbooksList.Add(textbooks);
HttpContext.Session.Set<List<Textbooks>>("textbooks", textbooksList);
// ViewData["isDisplay"] = true;
return View("view_appraisals", textbooksList);
}
else
{
return View("Bad");
}
}
public IActionResult view_appraisals()
{
if (HttpContext.Session.Get<List<Textbooks>>("textbooks") == null)
{
HttpContext.Session.Set<List<Textbooks>>("textbooks", textbooksList);
}
else
{
textbooksList = HttpContext.Session.Get<List<Textbooks>>("textbooks");
}
if (textbooksList.Count>0)
{
// ViewData["isDisplay"] = true;
return View("view_appraisals", textbooksList);
}
else
{
return View("bad");
}
}
The result like this: (if the entered data correct, it will directly redirect to the view_appraisal page)
You might want to hide the "View Appraisals" navigation link if there have no data, and, if there has records, display the "View Appraisals" navigation link. If that is the case, try to modify the navigation code (in the _layout.cshtml) as below:
#{
var isdisplay = "none"; //default value, hidden the View Appraisals link.
if (ViewData["isDisplay"] != null)
{
isdisplay = "block";
}
}
<li class="nav-item">
<a class="nav-link text-dark" style="display:#isdisplay" href ="~/Home/view_appraisals">View Appraisals</a>
</li>
Then, if you want to show the link, in the controller, set a value for "ViewData["isDisplay"]", code like this:
public IActionResult Index()
{
return View();
}
[HttpGet]
public IActionResult Appraise()
{
if (HttpContext.Session.Get<List<Textbooks>>("textbooks") != null)
{
ViewData["isDisplay"] = true;
}
return View();
}
[HttpPost]
public IActionResult Appraise(Textbooks textbooks)
{
if (ModelState.IsValid)
{
ViewData["Message"] = "Your textbook: " +
textbooks.title +
", Version: " +
textbooks.version +
" was priced at: " +
textbooks.price;
if (HttpContext.Session.Get<List<Textbooks>>("textbooks") != null)
{
textbooksList = HttpContext.Session.Get<List<Textbooks>>("textbooks");
}
textbooksList.Add(textbooks);
HttpContext.Session.Set<List<Textbooks>>("textbooks", textbooksList);
ViewData["isDisplay"] = true;
return View("view_appraisals", textbooksList);
}
else
{
return View("Bad");
}
}
public IActionResult view_appraisals()
{
if (HttpContext.Session.Get<List<Textbooks>>("textbooks") == null)
{
HttpContext.Session.Set<List<Textbooks>>("textbooks", textbooksList);
}
else
{
textbooksList = HttpContext.Session.Get<List<Textbooks>>("textbooks");
}
if (textbooksList.Count>0)
{
ViewData["isDisplay"] = true;
return View("view_appraisals", textbooksList);
}
else
{
return View("bad");
}
}
Then, the result like this:
I'm new to ruby, need to create a form for user registration, and user must be able to register limitless number of friends. Want to do it like so: begin with single form and add button. If user clicks on add button the first form is copied and so on. In the end there is only one submit button which submits all forms. Trying to do it, but can't understand how to pass limitless number of objects to the form. Now just passing one object:
participation_forms_controller.rb:
class ParticipationFormsController < ApplicationController
def new
#participation_form = ParticipationForm.new
end
...
The problem is I need to create some number of ParticipationForm objects but only user determine actual number of that objects. And as I understand , I need to pass the same number of objects from ruby controller to my html. But I don't know how many, so I can't do some sort of loop in controller like that:
class ParticipationFormsController < ApplicationController
def new
#participation_forms = []
<dont_know_how_many>.times do
#participation_forms << ParticipationForm.new
end
end
I've thought about some sort of dirty hack: copy all data from other forms to the first and then submit only the first. But want to do it in good fashion way as normal coders do. What I can do if I used python: just make one form with fieldnames like username_1, userdata_1, username_2, userdata_2 and so on, then just parse them on backend. But ruby is somewhat strict about what parameters i can pass to the controller, i must predefine them, so can't do that trick? What is my create controller:
def create
#participation_form = ParticipationForm.new(article_params)
#participation_form.save
render 'new'
end
private
def article_params
params.require(:participation_form).permit(
:name, :telephone, :email, :post, :image)
end
So how can I pass there something like name_999? No way, ruby is rigorous.
It will be awesome if in ruby I can use regexp to allow set of fields, just my fantasy-code:
def article_params
params.require(:participation_form).permit(
:re.match('^name_\d*$'))
end
If it will be real then I can use one form for this task.
frontend code snippet of-what-i-want
/* Latest compiled and minified JavaScript included as External Resource */jQuery(document).ready(function() {
var addFriendForm = function() {
$('.button-group__add-friend-btn').click(function() {
forms = $(".form-signin");
var first = forms.first();
var first_clone = first.clone();
first_clone_children = first_clone.children();
$(first_clone_children).each(function() {
if ($(this).hasClass('form-signin__file-upload')) {
file_upload_children = $(this).children();
file_upload_children.each(function() {
this.value = '';
});
}
else {
this.value = '';
}
});
var last = forms.last();
first_clone.insertAfter(last);
$('<hr class="container__hr">').insertAfter(last);
changeRegBtnText();
addDelBtn();
});
};
var changeRegBtnText = function(back_to_one=false) {
var one = 'register'
var plural = 'register with friends';
var btn = $('.button-group__add-reg-btn');
if (btn.text() == one) {
btn.html(plural);
}
else if (back_to_one) {
btn.html(one);
}
};
var addDelBtn = function() {
var del_btn = $("#friend_del_btn");
if (del_btn.hasClass("button-group__del-friend-btn_disabled")) {
del_btn.removeClass("button-group__del-friend-btn_disabled");
del_btn.addClass("button-group__del-friend-btn_active");
}
};
var deleteFriendForm = function() {
$('#friend_del_btn').click(function() {
forms = $(".form-signin");
hrs = $('.container__hr');
var last_fieldset = forms.last();
last_fieldset.remove();
var last_hr = hrs.last();
last_hr.remove();
if ($(".form-signin").length == 1) {
changeRegBtnText(back_to_one=true);
$("#friend_del_btn").addClass("button-group__del-friend-btn_disabled");
}
});
};
var submitForms = function() {
$(".button-group__add-reg-btn").on("click", function(e) {
$(".form-signin").each(function(){
$(this).trigger("submit");
console.log('submit');
});
});
}
addFriendForm();
deleteFriendForm();
submitForms();
});
.form-control {
margin-top: 10px;
margin-bottom: 10px;
height: auto;
padding: 10px;
font-size: 16px;
}
.form-signin {
max-width: 330px;
padding: 15px;
margin: 0 auto;
}
.container__hr {
background-color: #A9A9A9;
height: 1px;
width: 300px;
}
.form-signin__file-upload {
position: relative;
overflow: hidden;
margin-bottom: 10px;
height: 35px;
width: 100%;
}
.form-signin__file-upload-filename {
float: left;
color: #222;
margin-top: -3px;
}
.form-signin__file-upload-input {
position: absolute;
top: 0;
right: 0;
margin: 0;
padding: 0;
cursor: pointer;
opacity: 0;
filter: alpha(opacity=0);
}
.form-signin__file-upload-span {
line-height: 1.42;
color: black;
}
.button-group {
margin-left: auto;
margin-right: auto;
max-width: 330px;
padding-left: 15px;
padding-right: 15px;
}
.button-group__add-friend-btn,
.button-group__add-reg-btn {
margin-top: 10px;
margin-bottom: 10px !important;
width: 100%;
}
.button-group__del-friend-btn_disabled {
display: none !important;
}
.button-group__del-friend-btn_active {
margin-top: 10px;
margin-bottom: 10px !important;
width: 100%;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<h3 class="text-center">Register to conference</h3>
<form class="form-signin">
<input type="text" name="[participation_form]name" class="form-control" placeholder="Имя" required autofocus>
<input type="tel" name="[participation_form]telephone" class="form-control" placeholder="Телефон" required>
<input type="email" name="[participation_form]email" class="form-control" placeholder="Електропочта" required>
<input type="text" name="[participation_form]post" class="form-control" placeholder="Должность" required>
<div class="form-signin__file-upload btn btn-info" disabled="disabled">
<input class="form-signin__file-upload-filename">
<input type="file" name="[participation_form]image" class="form-control form-signin__file-upload-input" required>
<span class="form-signin__file-upload-span">аватар</span>
</div>
</form>
<div class="text-center button-group">
<button type="button" class="btn btn-default button-group__add-friend-btn">
<span class="glyphicon glyphicon-plus"></span> add friend
</button>
<button type="button" id="friend_del_btn" class="btn btn-default button-group__del-friend-btn_disabled">
<span class="glyphicon glyphicon-remove"></span> del friend
</button>
<button class="btn btn-lg btn-primary btn-block button-group__add-reg-btn" type="submit">register</button>
</div>
So, this is probably not a complete solution, but my first thing to point out is... you should only need a total of one ParticipationForm - you don't need to add multiple forms, just multiple sets of user-details fields.
Each set of user-fields will need to be uniquely grouped and identified eg the end-result (after the javascript has added the new fields ech time) would be something like below (note: I've just added a very simple version of the fields, not what you will eventually use with all the details):
<form class="form-signin">
<div class="user-field-set">
<input type="text" name="[participation_form][1]name" class="form-control" placeholder="Имя" required autofocus>
<input type="tel" name="[participation_form][1]telephone" class="form-control" placeholder="Телефон" required>
<input type="email" name="[participation_form][1]email" class="form-control" placeholder="Електропочта" required>
</div>
<div class="user-field-set">
<input type="text" name="[participation_form][2]name" class="form-control" placeholder="Имя" required autofocus>
<input type="tel" name="[participation_form][2]telephone" class="form-control" placeholder="Телефон" required>
<input type="email" name="[participation_form][2]email" class="form-control" placeholder="Електропочта" required>
</div>
*** submit button for all sets of user details goes here ***
</form>
I'm trying to place two Kendo UI widgets side-by-side within an Angular-UI modal window.
My problem is that they are getting place one below the other as in the embedded screen shot.
Note the Dimensions List on top (<li ng-repeat), and the Dimension Grid on the bottom. I'd like these to be side-by-side :
Here's the HTML template, which is part of the Angular Bootstrap modal :
<form class="form-horizontal">
<fieldset>
<!-- Form Name -->
<legend>User Dimensions</legend>
<div class="form-group">
<label class="col-md-4 control-label" for="radios-0">Choose One</label>
<div class="col-md-4">
<div class="radio">
<label for="radios-0">
<input name="radios" id="radio1" value="1" type="radio">
Defined Portfolios
</label>
</div>
<div class="radio">
<label for="radios-1">
<input name="radios" id="radio2" value="2" checked="checked" type="radio">
Specify Dimensions
</label>
</div>
</div>
<label class="col-md-4 control-label" for="radios-0">Dimensions</label>
<!-- *** KENDO SORTABLE *** -->
<div class="col-md-4">
<ul class="dim-list" kendo-sortable k-placeholder="settings.placeholder" k-hint="settings.hint">
<li ng-repeat="dim in settings.dimenDS">{{dim.name}}</li>
</ul>
</div>
<!-- *** KENDO GRID *** -->
<div class="col-md-8">
<span id="userDimenGrid" kendo-grid="settings.userDimenGrid"
k-data-source="settings.userDimenGridDS"
k-options="settings.userDimenGridOptions"
k-rebind="settings.userDimenGridOptions" />
</div>
</div>
</fieldset>
</form>
<style scoped>
.dim-list li{
list-style-type:none;
background-color:silver;
font-size:12px;
font-weight:bold;
width: 180px;
margin: 5px;
line-height: 30px;
text-align: center;
border-radius: 3px;
cursor:move;
}
li.hint {
display: block;
padding: 10px;
width: 200px;
background-color: #52aef7;
color: #fff;
}
li.hint:last-child {
border-radius: 4px;
}
li.hint span {
color: #fff;
}
li.placeholder {
background-color: #dceffd;
color: #52aef7;
text-align: right;
}
</style>
I would like this to be side by side, but having much trouble formatting it as such within this <form> .
final solution :
I ended up spending more time working with bootstrap classes row and/or row-fluid, as well as col-lg-4.
It turns out the standard "form-group" class won't exactly work with what I want to do. Of course, since it's not exactly a form. Rather I'm placing Kendo UI widgets side by side.
<form class="form-horizontal">
<fieldset>
<!-- Form Name -->
<legend>User Dimensions</legend>
<div class="form-group">
<label class="col-md-4 control-label" for="radios-0">Choose One</label>
<div class="row">
<div class="col-lg-4">
<div class="radio">
<label for="radios-0">
<input name="radios" id="radio1" value="1" type="radio">
Defined Portfolios
</label>
</div>
<div class="radio">
<label for="radios-1">
<input name="radios" id="radio2" value="2" checked="checked" type="radio">
Specify Dimensions
</label>
</div>
</div>
<div class="col-lg-8"></div>
</div>
<div class="row-fluid">
<div class="col-lg-3">
<ul class="dim-list" kendo-sortable k-hint="settings.hint" k-move="settings.move" k-end="settings.end" k-placeholder="settings.placeholder">
<li ng-repeat="dim in settings.dimenDS">{{dim.name}}</li>
</ul>
</div>
<div class="col-lg-8">
<span id="userDimenGrid" kendo-grid="settings.userDimenGrid"
k-data-source="settings.userDimenGridDS"
k-options="settings.userDimenGridOptions"
k-rebind="settings.userDimenGridOptions" />
</div>
</div>
</div>
</fieldset>
</form>
<style scoped>
.dim-list li{
list-style-type:none;
display: inline-block;
background-color:silver;
font-size:12px;
font-weight:bold;
width: 180px;
margin: 5px;
line-height: 30px;
text-align: center;
border-radius: 3px;
cursor:move;
}
li.hint {
display: block;
padding: 10px;
width: 200px;
background-color: #52aef7;
color: #fff;
}
li.hint:last-child {
border-radius: 4px;
}
li.hint span {
color: #fff;
}
li.placeholder {
background-color: #dceffd;
color: #52aef7;
text-align: right;
}
I have two tabs. In each tab I have a textbox with validation.
#model WebApplication2.Models.MyViewModel
#{
ViewBag.Title = "Test";
}
<h2>Test</h2>
<style>
.tabs li {
list-style: none;
display: inline;
}
.tabs a {
padding: 5px 10px;
display: inline-block;
background: #666;
color: #fff;
text-decoration: none;
}
.tabs a.active {
background: #fff;
color: #000;
}
</style>
#using (Html.BeginForm())
{
<ul class='tabs'>
<li><a href='#tab1'>Tab 1</a></li>
<li><a href='#tab2'>Tab 2</a></li>
</ul>
<div id='tab1'>
<h3>Section 1</h3>
#Html.TextBoxFor(m => m.FirstName)
#Html.ValidationMessageFor(m => m.FirstName)
</div>
<div id='tab2'>
<h3>Section 2</h3>
#Html.TextBoxFor(m => m.FirstName)
#Html.ValidationMessageFor(m => m.FirstName)
</div>
<input type="submit" value="Submit" />
}
#section Scripts{
#Scripts.Render("~/bundles/jqueryval")
<script>
// Wait until the DOM has loaded before querying the document
$(document).ready(function () {
$('ul.tabs').each(function () {
// For each set of tabs, we want to keep track of
// which tab is active and it's associated content
var $active, $content, $links = $(this).find('a');
// If the location.hash matches one of the links, use that as the active tab.
// If no match is found, use the first link as the initial active tab.
$active = $($links.filter('[href="' + location.hash + '"]')[0] || $links[0]);
$active.addClass('active');
$content = $($active.attr('href'));
// Hide the remaining content
$links.not($active).each(function () {
$($(this).attr('href')).hide();
});
// Bind the click event handler
$(this).on('click', 'a', function (e) {
// Make the old tab inactive.
$active.removeClass('active');
$content.hide();
// Update the variables with the new link and content
$active = $(this);
$content = $($(this).attr('href'));
// Make the tab active.
$active.addClass('active');
$content.show();
// Prevent the anchor's default click action
e.preventDefault();
});
});
});
</script>
}
This is what gets rendered for both tabs:
<div id="tab1">
<h3>Section 1</h3>
<input data-val="true" data-val-required="The FirstName field is required." id="FirstName" name="FirstName" type="text" value="">
<span class="field-validation-valid" data-valmsg-for="FirstName" data-valmsg-replace="true"></span>
</div>
<div id="tab2" style="display: none;">
<h3>Section 2</h3>
<input id="FirstName" name="FirstName" type="text" value="">
<span class="field-validation-valid" data-valmsg-for="FirstName" data-valmsg-replace="true"></span>
</div>
The difference are these two:
data-val="true" data-val-required="The FirstName field is required."
ViewModel:
public class MyViewModel
{
[Required]
public string FirstName { get; set; }
}
What I want to do is to have validation for both textboxes independently och each other. That is, when the user clicks on the first tab I want to be able to validate the textbox in the first tab and if the user clicks on the second tab I want to validate the textbox in the second tab.
How to do this with only one property in my viewmodel class? Imagine having 50 tabs. I wouldn't want to have 50 properties in my viewmodel class.
I am new to MVC, i want to create a login control and for i have write the below code in view:
#using (Html.BeginForm("LoginControl", "Login"))
{
<div style="float: left; line-height: 36px;">
#Html.ValidationSummary()
<div style="float: left; margin-right: 20px;">
UserName :
</div>
<div style="float: right;">#Html.TextBoxFor(o => o.login.UserName)
</div>
<br />
<div style="float: left; margin-right: 20px;">
Password :
</div>
<div style="float: right;">#Html.TextBoxFor(o => o.login.UserPassword)</div>
<br />
<div style="float: left; margin-right: 20px;">
</div>
<input type="button" value="Login" id="Login" title="Login" />
</div>
}
in controller my code is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication2.Controllers
{
public class LoginController : Controller
{
//
// GET: /Default1/
public ActionResult Index()
{
return View();
}
public ActionResult LoginControl(String UserName, String UserPassword)
{
string result = "";
if (UserName == "ram" && UserPassword == "ram123")
{
result = "1";
}
if (result == "1")
{
return View("LoginControl");
}
else
{
ModelState.AddModelError("", "Invalid username or password");
return View("Index");
}
}
}
}
I am not able to get why it is working, please help me.
ok first of all change the input type of button to submit:
<input type="button" value="Login" id="Login" title="Login" />
Now Change the View Code as below:
#using (Html.BeginForm("LoginControl", "Login"))
{
<div style="float: left; line-height: 36px;">
#Html.ValidationSummary()
<div style="float: left; margin-right: 20px;">
UserName :
</div>
<div style="float: right;">#Html.TextBox("UserName")
</div>
<br />
<div style="float: left; margin-right: 20px;">
Password :
</div>
<div style="float: right;">#Html.TextBox("UserPassword")
</div>
<br />
<div style="float: left; margin-right: 20px;">
</div>
<input type="submit" value="Login" id="Login" title="Login" />
</div>
}
Hope this will help you.