Previous component doesn't vanish after navigation method execution - c#

Previous component doesn't vanish after navigation method execution. My new component appears in the bottom of old component. What should I do to display new navigated component alone? When I redirect straight to new component blank view is displayed. To generate component I used ng g c componentName.
Navigation:
this.router.navigate(['dashboard'], {relativeTo: this.route});
New component:
export class DashboardComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
Router:
const routes: Routes = [
{ path : "dashboard", component : DashboardComponent},
{path : "**", component: PageNotFoundComponent}]
#NgModule({
imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'})],
exports: [RouterModule]
})
export class AppRoutingModule { }
export const routingComponents =[DashboardComponent, PageNotFoundComponent]
Project structure:
Template
<div class="bg">
<div class="container">
<div class="row">
<div class='col-md-3'></div>
<div class="col-md-6">
<div class="login-box well">
<legend>Sign In</legend>
<div class="form-group">
<input id="username-email" placeholder="E-mail or Username" type="text" [(ngModel)]="username" class="form-control" />
</div>
<div class="form-group">
<input id="password" placeholder="Password" type="text" class="form-control" [(ngModel)]="password"/>
</div>
<div class="input-group">
<div class="checkbox">
<label>
<input id="login-remember" type="checkbox" name="remember" [(ngModel)]="remember"> Remember me
</label>
</div>
</div>
<div class="form-group">
<input (click)="loginButtonClick()" id="login_button" class="btn btn-default btn-login-submit btn-block m-t-md" value="Login" />
</div>
<span class='text-center'>Forgot Password?</span>
</div>
</div>
<div class='col-md-3'></div>
</div>
</div>
<router-outlet>
</router-outlet>
<footer class="fixed-bottom">
<!-- Copyright -->
<div class="footer-copyright text-center py-3">© 2018 Copyright:
worko.com
</div>
<!-- Copyright -->
</footer>
</div>

With the information that you've provided so far, it looks like you've been trying to navigate from the sign in page to the dashboard.
You're still able to see the Login Page fields along with the Dashboard content at the bottom.
And this makes sense since the Router is going to load the contents of the Dashboard Component in the view in the router-outlet. But your Login Component is not a part of a Component that's loaded on the router-outlet.
In such a case, you would create a LoginComponent` with the following content:
<div class="bg">
<div class="container">
<div class="row">
<div class='col-md-3'></div>
<div class="col-md-6">
<div class="login-box well">
<legend>Sign In</legend>
<div class="form-group">
<input id="username-email" placeholder="E-mail or Username" type="text" [(ngModel)]="username" class="form-control" />
</div>
<div class="form-group">
<input id="password" placeholder="Password" type="text" class="form-control" [(ngModel)]="password" />
</div>
<div class="input-group">
<div class="checkbox">
<label>
<input id="login-remember" type="checkbox" name="remember" [(ngModel)]="remember"> Remember me
</label>
</div>
</div>
<div class="form-group">
<input (click)="loginButtonClick()" id="login_button" class="btn btn-default btn-login-submit btn-block m-t-md" value="Login" />
</div>
<span class='text-center'>Forgot Password?</span>
</div>
</div>
<div class='col-md-3'></div>
</div>
</div>
</div>
And your RouterConfig will then look something like this:
const routes: Routes = [{
path: "dashboard",
component: DashboardComponent,
canActivate: [CanActivateDashboard], // This is a guard that you'll have to add
},
{
path: "login",
component: LoginComponent
},
{
path: "**",
component: PageNotFoundComponent
}
]
#NgModule({
imports: [RouterModule.forRoot(routes, {
onSameUrlNavigation: 'reload'
})],
exports: [RouterModule]
})
export class AppRoutingModule {}
export const routingComponents = [DashboardComponent, PageNotFoundComponent]
By default, you'll load the /login route through which, your user will see the contents of the LoginComponent in the View. Since this will now be loaded using Router, and the contents will be loaded on the <router-outlet>, only the DashboardComponent contents will be loaded on the <router-outlet> once the user is navigated to /dashboard route.
PS: Note that the unauthorized user should not be able to directly navigate to /dashboard. So you will also have to create a Guard in order to prevent that.

Related

Angular 6 registration form not sending

I'm doing a project an asp.net angular 6 project and am trying to include a registration and login form. So far my login form is working but my registration form isn't doing anything when pressing the register button. I'm following the same logic from my login form, I was wondering if anyone could point out to me why it isn't working.
register.component.html
<div class="container card" style="width:40rem;">
<div class="row justify-content-center card-header bg-primary" >
<div class="col">
<h2 class="text-center text-white mb-4">Register</h2>
</div>
</div>
<div class="row justify-content-center card-body mt-2">
<div class="col-6">
<form (ngSubmit)="onRegister()" [formGroup]="registerForm">
<div class="form-row">
<div class="col">
<label>
First name
<input class="form-control" type="text" formControlName="firstName"/>
</label>
<span class="help-block text-danger" *ngIf="registerForm.get('firstName').touched && registerForm.get('firstName').invalid">First name is required.</span>
</div>
</div>
<div class="form-row">
<div class="col">
<label>
Last name
<input class="form-control" type="text" formControlName="lastName"/>
</label>
<span class="help-block text-danger" *ngIf="registerForm.get('lastName').touched && registerForm.get('lastName').invalid">Last name is required.</span>
</div>
</div>
<div class="form-row">
<div class="col">
<label>
Address
<input class="form-control" type="text" formControlName="address"/>
</label>
<span class="help-block text-danger" *ngIf="registerForm.get('address').touched && registerForm.get('address').invalid">Address is required.</span>
</div>
</div>
<div class="form-row">
<div class="col">
<label>
E-mail
<input type="email" class="form-control" formControlName="email"/>
</label>
<span class="help-block text-danger" *ngIf="registerForm.get('email').touched && registerForm.get('email').invalid">Email is required and must be a valid email address.</span>
</div>
</div>
<div class="form-row">
<div class="col">
<label>
Date of Birth
<input type="date" class="form-control" formControlName="dateOfBirth"/>
</label>
<span class="help-block text-danger" *ngIf="registerForm.get('dateOfBirth').touched && registerForm.get('dateOfBirth').invalid">Date of birth is required.</span>
</div>
</div>
<div class="form-row">
<div class="col">
<label>
Password
<input type="password" class="form-control" formControlName="password"/>
</label>
<span class="help-block text-danger" *ngIf="registerForm.get('password').touched && registerForm.get('password').invalid">
<span *ngIf="registerForm.get('password').errors['passwordComplexity']" class="help-block d-block">The password needs to start with a letter and contain a number and a special character.</span>
<span *ngIf="registerForm.get('password').errors['passwordLength']" class="help-block d-block">The password must be at least 8 characters long.</span>
</span>
</div>
</div>
<div class="form-row">
<div class="col">
<label>
Security question
<select class="form-control" formControlName="securityQuestion">
<option *ngFor="let question of securityQuestions" value="{{question.id}}">{{question.question}}</option>
</select>
</label>
<span class="help-block text-danger" *ngIf="registerForm.get('securityQuestion').touched && registerForm.get('securityQuestion').invalid">Answer to security question is required</span>
</div>
</div>
<div class="form-row">
<div class="col">
<label>
Answer to security question
<input type="text" class="form-control" formControlName="securityAnswer"/>
</label>
<span class="help-block text-danger" *ngIf="registerForm.get('securityAnswer').touched && registerForm.get('securityAnswer').invalid">Answer to security question is required</span>
</div>
</div>
<div class="form-row">
<div class="col text-right">
<button class="btn btn-primary mr-2" [disabled]="registerForm.invalid">
Sign up
</button>
<a class="mr-2" [routerLink]="['/account']">
<button class="btn btn-warning">
Cancel
</button>
</a>
</div>
</div>
</form>
</div>
</div>
</div>
register.component.ts
import {Component, OnInit} from "#angular/core";
import {FormControl, FormGroup, Validators} from "#angular/forms";
import {MessageService} from "../../services/message.service";
import {ApiMethod, ApiService} from "../../services/api.service";
import {PasswordValidator} from "../../shared/validators/password.validator";
import {User, UserUpdateResult} from "../../shared/user-model";
import {HttpClient} from "#angular/common/http";
import {SecurityQuestion} from "../../shared/security.question.model";
#Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit{
public securityQuestions: SecurityQuestion[] = [];
public registerForm: FormGroup = new FormGroup({
firstName: new FormControl(null, Validators.required),
lastName: new FormControl(null, Validators.required),
address: new FormControl(null, Validators.required),
email: new FormControl(null, [Validators.email, Validators.required]),
dateOfBirth: new FormControl(null, Validators.required),
password: new FormControl(null, [Validators.required, PasswordValidator.Length, PasswordValidator.Complexity]),
securityQuestion: new FormControl(1, Validators.required),
securityAnswer: new FormControl(null, [Validators.required]),
});
constructor(public messageService: MessageService,
public apiService: ApiService,
public httpClient: HttpClient){}
ngOnInit(): void {
this.httpClient.get(this.apiService.getUrl(ApiMethod.GetSecurityQuestions)).subscribe((questions: SecurityQuestion[]) => {
this.securityQuestions = questions;
})
}
public onRegister(){
const user = new User();
user.fullName = this.registerForm.value.firstName + ' ' + this.registerForm.value.lastName;
user.password = this.registerForm.value.password;
user.email = this.registerForm.value.email;
user.address = this.registerForm.value.address;
user.dateOfBirth = new Date(this.registerForm.value.dateOfBirth);
const securityQuestion = new SecurityQuestion();
securityQuestion.id = this.registerForm.value.securityQuestion;
securityQuestion.answer = this.registerForm.value.securityAnswer;
user.securityQuestion = securityQuestion;
this.httpClient.post(this.apiService.getUrl(ApiMethod.UserSelfRegister), user).subscribe((result: UserUpdateResult) => {
if(result == UserUpdateResult.UsernameTaken){
this.messageService.error('User cannot be created', 'This user is already registered.');
return;
}
this.messageService.success('User registered', 'Waiting for activation. Please check your inbox for an email once your account has been activated.');
this.registerForm.reset();
});
}
}
Add type="submit" in button tag
<button type="submit" class="btn btn-primary mr-2" [disabled]="registerForm.invalid">
Sign up
</button>
You can add type="submit" to your button tag or you can remove (ngSubmit)="onRegister()" from your form tag and add (click)="onRegister()" to your button tag.

C# Razor pages Partial View Model is null on submit

I am new to Razor pages and trying to create a page with a partial view. The partial view has a dropdownlist and a text input for Quantity field and a submit button. The Partial View renders correctly but when I click on the Submit button the Model passed to the Code behind has no value.
Here is the code I have
_PartialAddons.cshtml
#*
For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*#
#{
}
#model Public.Areas.Register.AddonListDto
<form method="post">
#Html.HiddenFor(Model => Model.Quantity)
<div style="padding:5px;">
<b>NZD $45</b>
</div>
<div>
<div style="padding:5px;">
<select id="skuSelect" asp-for="SelectedSkus" asp-items="#(new SelectList(Model.AddonSkus,"SkuId","SkuName"))" class="form-control">
<option>Please select one</option>
</select>
</div>
<div style="padding:5px;">
<input type="hidden" name="handler" value="Quantity" />
<input asp-for="Quantity" name="Quantity" class="form-control ng-untouched ng-pristine ng-valid" max="999" min="0" style="width:150px;" type="number" value="0" id="#Model.Id">
</div>
</div>
<div style="padding:5px;">
<a class="btn green" asp-page-handler="AddToCart">Add to Cart</a>
</div>
</form>
This is the Main Page
#foreach (var addons in Model.StoreAddonList)
{
<div class="panel card panel-default" style="margin-top:10px;">
<div class="panel-heading card-header" role="tab">
<div class="panel-title">
<div class="accordion-toggle" role="button" aria-expanded="true">
<div accordion-heading="" style="width:100%;">
#addons.Title
<i class="pull-right float-xs-right glyphicon glyphicon-chevron-down"></i>
</div>
</div>
</div>
</div>
<div class="panel-collapse collapse in show" role="tabpanel" style="overflow: visible; height: auto; display: block;" aria-expanded="true" aria-hidden="false">
<div class="panel-body card-block card-body">
<div style="padding-top:10px;background-color:#ffffff;clear:both;">
<div style="width:100%">
<div style="float:left;width:20%;text-align:left;">
Name
</div>
<div style="float:left;width:30%;padding-left:10px;">
#addons.Description
</div>
</div>
<div style="float:left;width:40%;padding-left:10px;">
<div>
#{
await Html.RenderPartialAsync("_PartialAddons.cshtml", addons);
}
</div>
</div>
<div style="clear:both;">
</div>
</div>
</div>
</div>
</div>
}
This is the Index.cshtml.cs to handle the submit
public ActionResult OnGetAddToCart(AddonListDto addOnList)
{
var sass = Quantity;
var tass = SelectedSkus;
return null;
}
The AddonListDto is null on the OnGetAddToCart Method. Have been trying to get this working for the past two days. Any help would be greatly appriciated
If you want to submit your data, you need to use OnPost instead of OnGet in razor pages and set the handler name in the <form> tag. For example:
handler:
public ActionResult OnPostAddToCart(AddonListDto addOnList)
partial view:
#model Public.Areas.Register.AddonListDto
<form method="post" asp-page-handler="AddToCart">
#Html.HiddenFor(Model => Model.Quantity)
<div style="padding:5px;">
<b>NZD $45</b>
</div>
<div>
<div style="padding:5px;">
<select id="skuSelect" asp-for="SelectedSkus" asp-items="#(new SelectList(Model.AddonSkus,"SkuId","SkuName"))" class="form-control">
<option>Please select one</option>
</select>
</div>
<div style="padding:5px;">
<input type="hidden" name="handler" value="Quantity" />
<input asp-for="Quantity" name="Quantity" class="form-control ng-untouched ng-pristine ng-valid" max="999" min="0" style="width:150px;" type="number" value="0" id="#Model.Id">
</div>
</div>
<div style="padding:5px;">
<input type="submit" value="Add To Cart" class="btn btn-primary" />
</div>
</form>

ReactJS.Net Server Side Rendering Not Initializing Handlers

New to reactjs.net. I did my best to follow the instructions on the https://reactjs.net/guides/server-side-rendering.html website but i am still getting the following reference error re: my component: Signup is not defined. The page renders but the Signup component doesnt seem to be there. What am I doing wrong?
ReactConfig.cs:
public static void Configure()
{
ReactSiteConfiguration.Configuration
.AddScript("~/Scripts/jsx/welcome.jsx")
.AddScript("~/Scripts/jsx/navbar.jsx")
.AddScript("~/Scripts/jsx/login.jsx")
.AddScript("~/Scripts/jsx/Signup.jsx")
.AddScript("~/Scripts/jsx/about.jsx")
.AddScript("~/Scripts/jsx/contact.jsx");
}
SignUp.cshtml:
#{
ViewBag.Title = "Sign Up";
}
#Html.React("Signup", new { })
#section scripts{
#Scripts.Render("~/bundleSignUp")
#Html.ReactInitJavaScript()
}
class Signup extends React.Component {
constructor(props) {
super(props);
this._onSubmit = this._onSubmit.bind(this);
}
_onSubmit(e) {
console.log("HERE WE GO");
}
render() {
return (
<div>
<NavBar />
<form className="container container-fluid">
<div className="pullDown">
<div className="row">
<div className="col-lg-6 col-md-7 col-sm-8">
<div className="form-group">
<label htmlFor="exampleInputEmail1">Email address</label>
<input type="email" className="form-control" id="exampleInputEmail1" placeholder="Enter email" ref="email" />
</div>
</div>
</div>
<div className="row">
<div className="col-lg-6 col-md-7 col-sm-8">
<div className="form-group">
<label htmlFor="exampleInputPassword1">Password</label>
<input type="password" className="form-control" id="exampleInputPassword1" placeholder="Enter Password" ref="passWd" />
</div>
</div>
</div>
<div className="row">
<div className="btn btn-success" onClick={this._onSubmit}>Submit</div>
</div>
</div>
</form>
</div>
);
}
}

Is there any good reason NOT to use a ViewComponent instead of a Partial View in core MVC?

I'm new to MVC and decided to start with .net-core, so I don't have much understanding of the differences in core vs. older versions. I did find the below question which offers some insight but hasn't helped me to decide whether I can basically ignore partial views.
Why should we use MVC 6 Feature View Components over Partial View: What is the difference?
My question is simply - if I can do something with a ViewComponent, is there any good reason not to?
Many Thanks!
Example provided below for context.
Main view calls:
ViewComponent:
<div class="modal-body" ID="modalPersonInner">
#await Component.InvokeAsync("CreatePerson", new Person())
</div>
Versus Partial View:
<div class="modal-body" ID="modalPersonInner">
#{ await Html.RenderPartialAsync("People/CreatePartialView", new Person());}
</div>
Javascript (personCreateForm is a form within the partial view/view component):
var submitPersonCreate = function(evt) {
evt.preventDefault();
if ($(this).valid())
{
$.ajax({
type: "POST",
url: '#Url.Action("CreatePartial", "People")',
data: $('#personCreateForm').serialize(),
success(data) {
if (data === true)
window.location.reload();
else
$('#modalPersonInner').html(data);
}
});
}
return false;
}
$('#personCreateForm').submit(submitPersonCreate);
Controller code:
public async Task<IActionResult> CreatePartial(
[Bind("AddressLine1,AddressLine2,AddressLine3,AddressLine4,City,Country,Email,Forename,MobileNumber,Postcode,Region,Surname,TelephoneNumber")] Person person)
{
if (ModelState.IsValid)
{
_context.Add(person);
await _context.SaveChangesAsync();
return Json(true);
}
//PARTIAL VIEW VERSION
//return PartialView("People/CreatePartialView",person);
//VIEWCOMPONENT VERSION
return ViewComponent("CreatePerson", person);
}
ViewComponent code:
public class CreatePersonViewComponent : ViewComponent
{
private readonly AppDbContext db;
public CreatePersonViewComponent(AppDbContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(Person person )
{
return View(person ?? new Person());
}
}
And finally the Razor page which is the same for both:
#model Person
<form ID="personCreateForm">
<div class="form-horizontal">
<h4>Customer</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Forename" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Forename" class="form-control" />
<span asp-validation-for="Forename" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="Surname" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Surname" class="form-control" />
<span asp-validation-for="Surname" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="Country" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Country" class="form-control" Value="UK" />
<span asp-validation-for="Country" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="Region" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Region" class="form-control" />
<span asp-validation-for="Region" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="City" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="City" class="form-control" />
<span asp-validation-for="City" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="AddressLine1" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="AddressLine1" class="form-control" />
<span asp-validation-for="AddressLine1" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="AddressLine2" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="AddressLine2" class="form-control" />
<span asp-validation-for="AddressLine2" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="Postcode" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Postcode" class="form-control" />
<span asp-validation-for="Postcode" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="MobileNumber" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="MobileNumber" class="form-control" />
<span asp-validation-for="MobileNumber" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="TelephoneNumber" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="TelephoneNumber" class="form-control" />
<span asp-validation-for="TelephoneNumber" class="text-danger" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
</form>
It's a really good question. Yes, there are cases where you are better off implementing your code with a partial view than with a View Component. If the View Component isn't going to have any appreciable amount of logic (as is the case in your example) then you should use a partial view instead.
View Components are a great way to compartmentalize logic, and in some ways can be thought of as a partial view that contains it's own logic. But if there isn't any logic that needs to be compartmentalized with the partial view then it's probably best to not use a View Component. In such a case using a View Component increases the coding complexity (there is another place to look to see how the code works) but doesn't provide any real benefit. In general, you should only increase code complexity to the extent that the benefits received from that added complexity are greater than the "cost" of that complexity.
I hope that doesn't sound too theoretical. It basically boils down to this: if there is logic that you want to package up with the partial view so that you can use that component over and over, then use a View Component, but if there isn't any logic that you need to package up with it then use a partial view.
It appears that View Components still (as of July 2016) have some unsolved problems related to the javascript and css loading. Please check:
https://blog.mariusschulz.com/2015/11/26/view-components-in-asp-net-mvc-6

Inline form not working correctly

Trying to get an inline form out of bootstrap using the class form-inline. However, I'm encountering some unexpected behavior and I'm using exactly the same code as listed on the Boostrap official page.
This is what I get:
The code:
#using (Html.BeginForm("Edit", "Index", FormMethod.Post, new { #class = "form-inline" }))
{
<div class="form-group">
<label for="new-value">Enter new value: </label>
<input type="text" id="new-value" class="form-control" />
</div>
<div class="checkbox">
<label>
Public: <input type="checkbox" />
</label>
</div>
<input type="submit" class="btn btn-primary" />
}
When I remove the form-control class from the text box I get the wanted result, but I don't have the cool text box then:
I'm aware of the warning from bootstrap:
This only applies to forms within viewports that are at least 768px wide.
But this is on a large screen and the form width is 1160px.
I have edited your code.
Hope this is what you wanted!
HTML
<form class="form-inline">
<div class="form-group">
<label for="new-value">Enter new value: </label>
<input type="text" id="new-value" class="form-control" />
</div>
<div class="form-group">
<div class="checkbox">
<label> Public:
<input type="checkbox" />
</label>
</div>
</div>
<div class="form-group">
<input type="submit" class="btn btn-primary" />
</div>
</form>
Check this for the working model http://www.bootply.com/ZWGwdEcnva

Categories

Resources