How to show success or failure message in angular? - html

user.component.html
<form #ff="ngForm">
<input type="text" name="fname" placeholder="User Name" [(ngModel)] = "selectedUser.fname"/><br/><br/>
<input type="number" name="age" placeholder="age" [(ngModel)] = "selectedUser.age"/><br/><br/>
<input type="radio" name="sex" value="male" [(ngModel)] = "selectedUser.sex"/> Male<br/><br/>
<input type="radio" name="sex" value="female" [(ngModel)] = "selectedUser.sex"/> Female<br/><br/>
<input type="button" name="submit" value="submit" (click)="createUserData(ff.value)">
</form>
user.component.ts
import { Component, OnInit } from '#angular/core';
import { UserService } from '../../service/user.service';
#Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
constructor(private us:UserService) { }
user: any;
selectedUser: any = {fname:null, age: null, sex: null};
ngOnInit(): void {
}
createUserData(ff){
this.us.createform(ff).subscribe((user:any)=>{
console.log("Success register");
});
}
}
I am new in angular and I am trying to insert form data in database using web API to mysqli which is working fine. Now, I want to show success or failure message in my user.component.html page. I want when I click on submit button the page reload and show success or failure message. So, How can I do this please help me.
Thank you

You don't need to reload the page. You can choose to navigate to another component/page, or you can show a Popup dialog or you could render ad different content.
here a very simple example in order to render a different content:
registerSucess:boolean = false;
createUserData(ff){
this.us.createform(ff).subscribe((user:any)=>{
console.log("Success register");
this.registerSucess=true;
});
}
and in the tempalte:
<form #ff="ngForm" *ngIf="!registerSucess">
<input type="text" name="fname" placeholder="User Name" [(ngModel)] = "selectedUser.fname"/><br/><br/>
<input type="number" name="age" placeholder="age" [(ngModel)] = "selectedUser.age"/><br/><br/>
<input type="radio" name="sex" value="male" [(ngModel)] = "selectedUser.sex"/> Male<br/><br/>
<input type="radio" name="sex" value="female" [(ngModel)] = "selectedUser.sex"/> Female<br/><br/>
<input type="button" name="submit" value="submit" (click)="createUserData(ff.value)">
</form>
<h1 *ngIf="registerSucess"> Register Success :D </h1>
or you could use the variavle userinstead of registerSuccess, might be simpler

Create a string variable in user.component.ts to hold the message
export class UserComponent implements OnInit {
message = '';
...
Add an element to the html to contain the message, I'll use a <p>. Double curly brackets {{ }} allow you to insert a variable from the component.
<p>{{message}}</p>
Now simply updating the message in the component will update the html
createUserData(ff){
this.message = "Creating User Data..."
this.us.createform(ff).subscribe((user:any)=>{
this.message = "Success!"
});
}

In your code:
this.us.createform(ff).subscribe((user:any) => {
console.log("Success Register")
});
The code in the 'subscribe' delta function is executed every time a response is received through the 'createform' function. So here you can input some sort of mechanism to trigger you popup.
You need a popup window to be shown, which comes down to what sort of UI components you are using. The popup can be written in your html, and only shown through a flag that you activate in the subscribe delta function, and then disable when pressing or closing the popup.
I'd recommend using something like bootstrap for UI components.

Related

Display only shows last value of an Angular for loop even though devtools HTML has correct values

I'm using a for loop to display different sections of my blog for editing purposes.
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute, Route, ParamMap } from '#angular/router';
import { HttpClient } from '#angular/common/http';
import { Content } from '../model/Content';
#Component({
selector: 'app-edit-story',
templateUrl: './edit-story.component.html',
styleUrls: ['./edit-story.component.css']
})
export class EditStoryComponent implements OnInit {
story: any;
storyName: any;
isMe: boolean= false;
constructor(private route: ActivatedRoute, private httpClient: HttpClient) { }
ngOnInit(): void {
if (localStorage.getItem('userId')=='62e348924d52fa7420bb96bc') {
this.isMe = true;
}
this.storyName = this.route.snapshot.paramMap.get('storyName');
var url = 'http://localhost:3002/api/stories/' + this.storyName;
this.httpClient.get(url).subscribe(data => {
this.story = data;
console.log(this.story);
})
}
editStory() {
}
addContent() {
var newContent = new Content("", "", "");
this.story.contents.push(newContent);
}
}
<div *ngIf="isMe">
<form #editStoryForm = "ngForm" (ngSubmit)="editStory()" class="addStory">
<label for="title">Title</label>
<input name="title" type="text" [(ngModel)]="story.title" req/>
<label for="subtitle">Subtitle</label>
<input type="subtitle" [(ngModel)]="story.subtitle" name="subtitle" req>
<label for="name">Name</label>
<input type="name" [(ngModel)]="story.name" name="name" req>
<button (click)="addContent()">Add Content</button>
<div *ngFor="let content of story.contents">
<label for="type">Type</label>
<select name='type' [(ngModel)]="content.type" value="{{content.type}}">
<option value=''>Pick one</option>
<option value='text' selected="selected">text</option>
<option value='image'>image</option>
</select>
<label for="text">Text</label>
<textarea name="text" cols="50" rows="7" [(ngModel)]="content.text">{{content.text}}</textarea>
<label for="url">url</label>
<input name="url" type="text" value="{{content.url}}" [(ngModel)]="content.url">
</div>
<button type="submit">Edit</button>
</form>
</div>
In the console.log to display the story, the contents array appears fine. Even when I open devtools and check the HTML elements, the values are correct.
devtools showing the innerHTML values are all different
However the page itself has all these element with only the values of the last array item.
contarary to the devtools html, the page displays the last array values over and over
please help.
You are using template-driven forms. The problem is in the way you're registering the child controls using ngModel and the name attribute.
In your ngFor you do:
<textarea name="text" [(ngModel)]="content.text">{{content.text}}</textarea>
So basically you're assigning the same name to all children.
Instead, you should do something like this:
<div *ngFor="let content of story.contents; index as i">
<!-- other elements -->
<label for="text">Text</label>
<textarea name="{{ 'text-' + i }}" [(ngModel)]="content.text">
{{ content.text }}
</textarea>
<!-- other elements -->
</div>
You may also find the last section of this article helpful.
Cheers.

Is there a way to enable the autocomplete for angular reactive form?

I want to set on the autocomplete attribute for an angular form but it doesn't work as expected. It remembers only the values that I submitted only the first time and I would like to remember and suggest all the values no matter how many times I click on submit button.
Here is the stackblitz with the code that I tried.
<form
autocomplete="on"
(ngSubmit)="onSubmit()"
name="filtersForm"
[formGroup]="formGroup1"
>
<div>
<label>First Name</label>
<input
id="firstName"
name="firstName"
autocomplete="on"
formControlName="firstName"
/>
</div>
<div>
<label>Last Name</label>
<input
id="firstName"
name="lastName"
autocomplete="on"
formControlName="lastName"
/>
</div>
<button type="submit">Submit</button>
</form>
Here are the details about the autocomplete attribute that I used.
In Firefox, the autocomplete is working after several clicks on Submit button, the problem is in Chrome and Edge.
Is there a way to make the autocomplete to work for inputs inside the angular form?
I think, I have found a workaround, that only works with Template Driven Form.
TLDR;
What I have discovered while looking after this issue.
On first form submit autofill remember only first time submission values
form submit POST method can remember all values.
Yes, by looking at above, it clearly seems like 2nd way is suitable for us. But why would anybody do form POST for submitting form to BE. There should be better way to tackle this. Otherwise we would have to think of handling PostBack 😃😃 (FW like .Net does it by keeping hidden input's).
Don't worry we can do some workaround here to avoid form POST. I found an answer for handling POST call without page refresh.
Working JSBin with plain HTML and JS
AutoCompleteSaveForm = function(form){
var iframe = document.createElement('iframe');
iframe.name = 'uniqu_asdfaf';
iframe.style.cssText = 'position:absolute; height:1px; top:-100px; left:-100px';
document.body.appendChild(iframe);
var oldTarget = form.target;
var oldAction = form.action;
form.target = 'uniqu_asdfaf';
form.action = '/favicon.ico';
form.submit();
setTimeout(function(){
form.target = oldTarget;
form.action = oldAction;
document.body.removeChild(iframe);
});
}
Basically we change set few things on form attribute.
target="iframe_name" - Connects to iFrame to avoid page refresh.
method="POST" - POST call
url="/favicon" - API url to favicon (lightweight call)
In angular you can create an directive for the same.
import {
Directive, ElementRef, EventEmitter,
HostBinding, HostListener, Input, Output,
} from '#angular/core';
#Directive({
selector: '[postForm]',
})
export class PostFormDirective {
#HostBinding('method') method = 'POST';
#HostListener('submit', ['$event'])
submit($event) {
$event.preventDefault();
this.autoCompleteSaveForm(this.el.nativeElement);
}
constructor(private el: ElementRef) {}
autoCompleteSaveForm(form) {
let iframe = document.querySelector('iframe');
if (!iframe) {
iframe = document.createElement('iframe');
iframe.style.display = 'none';
}
iframe.name = 'uniqu_asdfaf';
document.body.appendChild(iframe);
var oldTarget = form.target;
var oldAction = form.action;
form.target = 'uniqu_asdfaf';
form.action = '/favicon.ico'; // dummy action
form.submit();
setTimeout(() => {
// set back the oldTarget and oldAction
form.target = oldTarget;
form.action = oldAction;
// after form submit
this.onSubmit.emit();
});
}
#Output() onSubmit = new EventEmitter();
ngOnDestroy() {
let iframe = document.querySelector('iframe');
if (iframe) {
document.body.removeChild(iframe);
}
}
}
Okay, so far everything went well. Then I started integrating this in formGroup(Model Driven Form), somehow it didn't worked. It does not store value next time these fields.
<form (ngSubmit)="onSubmit()" [formGroup]="formGroup1" autocomplete="on">
<div>
<label>First Name</label>
<input id="firstName" name="firstName" formControlName="firstName" />
</div>
<div>
<label>Last Name</label>
<input id="lastName" name="lastName" formControlName="lastName" />
</div>
<button>Submit</button>
</form>
Later I tried the same with Template Driven Form. It just worked like a charm! I did not went into the depth why it didn't work for Model Driven Form (perhaps that investigation could eat more time).
<form #form1="ngForm" ngForm postForm (onSubmit)="onSubmit(form1)">
<ng-container [ngModelGroup]="userForm">
<div>
<label>First Name</label>
<input name="firstName" [(ngModel)]="userForm.firstName" />
</div>
<div>
<label>Last Name</label>
<input name="lastName" [(ngModel)]="userForm.lastName" />
</div>
</ng-container>
<button>Submit</button>
</form>
Yeah, I just said in the begining it works only with Template Driven Form. So you would have to switch to Template. And one more important thing to note, you may think of creating dummy POST api call, that can be lightweight rather than hitting favicon.
Stackblitz
autocomplete attribute works only with submitted values. It has nothing to do with Angular.
https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete
If you need some custom behavior then you are better off creating your own component to autocomplete user's input, this way you can use some default values, add more of them on blur etc.
You just need to remove autocomplete="on" in input tag. With chrome, we only add attribute autocomplete="on" in form element and it will be cached all value that user input into input text. Result will be like this:
<form
autocomplete="on"
(ngSubmit)="onSubmit()"
name="filtersForm"
[formGroup]="formGroup1"
>
<div>
<label>First Name</label>
<input
id="firstName"
name="firstName"
formControlName="firstName"
/>
</div>
<div>
<label>Last Name</label>
<input
id="firstName"
name="lastName"
formControlName="lastName"
/>
</div>
<button type="submit">Submit</button>
</form>
You have to create an array with your desired options which should be displayed as autocomplete. You can have a look here https://material.angular.io/components/autocomplete/examples, there are multiple examples which should help you. Even if you're not using Angular Material, the logic would be the same

Pass value from Typescript to HTML. Error; [object HTMLInputElement]

I try to pass array values from a .ts file to a html file in a Angular Project.
The HTML file is:
<body>
<section id="login" class="d-flex justify-content-center flex-column align-items-center">
<form>
<div class="form-group">
<label>Firmware</label>
<input #firmware class="form-control" type="text" value= {{firmware}} readonly>
</div>
<div class="form-group">
<label>Bootloader</label>
<input #bootloader class="form-control" type="text" value= {{bootloader}} readonly>
</div>
</form>
</section>
</body>
and the .ts file is:
import { Component, OnInit } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Router, ActivatedRoute, ParamMap } from '#angular/router';
#Component({
selector: 'app-dual',
templateUrl: './dual.component.html',
styleUrls: ['./dual.component.scss']
})
export class DualComponent implements OnInit {
title = "";
constructor(private router: Router, private httpClient : HttpClient) { }
ngOnInit(): void {
var resultArray:number[] = [235,23]
var firmware = resultArray[0];
var bootloader = resultArray[1];
console.log("firmware",firmware);
console.log("bootloader",bootloader);
}
}
If i show the values via console.log they are shown right but if i try to show them in the HTML file the value in the textbox is "[object HTMLInputElement]"
Note: Im new in Angular and try to learn :)
Any tips?
Thank you!
Solution:
HTML:
<div class="form-group">
<label>Firmware</label>
<input class="form-control" type="text" value= {{firmware}} readonly>
</div>
<div class="form-group">
<label>Bootloader</label>
<input class="form-control" type="text" value= {{bootloader}} readonly>
</div>
TypeScript:
var resultArray:number[] = [235,23]
this.firmware = resultArray[0].toString();
this.bootloader = resultArray[1].toString();
console.log("firmware",this.firmware);
console.log("bootloader",this.bootloader);
I deleted my old answer, because I totally missed what was wrong. When you do this:
<input #firmware class="form-control" type="text" value= {{firmware}} readonly>
The #firmware creates a new local variable named firmware, which is equal to the HTML element it's contained in. It's that new local variable that is being displayed inside the curly braces, not the variable firmware which is defined in your DualComponent class.
Make sure you don't duplicate variable names like this, and the problem will go away.

What is the problem in my ngModel when I want to define a variable?

I want to use ngModel, but I have a problem.
This code is not running and it gives me an error.
This is my code:
contact-form.component.html:
<div class="container">
<form>
<div class="form-group">
<label for="firstName">First name</label>
<input ngModel #firstName="firstName" (change)="log(firstName)" id="firstName" type="text" class="form-control"/>
</div>
<div class="form-group">
<label for="comment">comment</label>
<textarea id="comment" rows="3" class="form-control"></textarea>
</div>
<button class="btn btn-primary">Enter</button>
</form>
</div>
contact-form.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-contact-form',
templateUrl: './contact-form.component.html',
styleUrls: ['./contact-form.component.css']
})
export class ContactFormComponent implements OnInit {
constructor() { }
ngOnInit() {
}
log(f) {
console.log(f);
}
}
and this error display in console:
Error: Template parse errors:
There is no directive with "exportAs" set to "firstName" (" <div class="form-group">
<label for="firstName">First name</label>
<input ngModel [ERROR ->]#firstName="firstName" (change)="log(firstName)" id="firstName" type="text" class="form-control"/>
"): ng:///AppModule/ContactFormComponent.html#4:23
What can I do?
modify your input tag in the form like the following :
<input #firstName="ngModel" (change)="log(firstName)"
type="text" class="form-control"/>
Note: if you you want to have Two-way data binding ( [(ngModel)]="propName" ):
<input #firstName="ngModel" (change)="log(firstName)" [(ngModel)]="firstName"
type="text" class="form-control"/>
You can try this:
<div class="form-group">
<label for="firstName">First name</label>
<input [(ngModel)]="firstName" #firstName (change)="log(firstName)" id="firstName" type="text" class="form-control"/>
</div>
for your input tag use this. this will breaking down Two-Way data binding.
<input #firstName (change)="log(firstName)" type="text">
- and to display its content use it as interpolation syntax in your template.
{{firstName.value}}
- after you done text input press enter and results will be in interpolation.
Second way of doing this is like..
in this case you need to define your property name in your component class too.
private firstName;
and in your template file
<input [ngModel]="firstName" (ngModelChange)="firstName = $event" >
{{ firstName }}
make sure you import FormsModule in main app module of your project.
import { FormsModule } from '#angular/forms';
If you want to access template reference variable in your component.ts file then your have to use #ViewChild () directives. and result of this available only in ngAfterViewInit() life cycle method.
#ViewChild ('firstName', { static: false} ) inputRefElm : ElementRef;
ngAfterViewInit(){
console.log(this.inputRefElm.nativeElement.value);
}

Passing interpolation value through ngModel

<input [(ngModel)]="newVariablesAttribute.Steps"
class="form-control"
type="text" readonly
name="{{newVariablesAttribute.Steps}}">
{{stepname}}
I want to pass stepname (which I am able to show in the frontend using interpolation) using ngModel.
But It is not working.
Didn't find any issue with your code. Steps might be undefined
Component
export class SomeComponent {
newVariablesAttribute = {
Steps: 'step'
};
stepname = 'abc';
}
html:
<input [(ngModel)]="newVariablesAttribute.Steps" class="form-control" type="text" readonly name="{{newVariablesAttribute.Steps}}">{{stepname}}
O/P
Since stepname is getting rendered in the UI, you can pass it to the ngModel directly like this right -
<input [(ngModel)]="stepname"
class="form-control"
type="text" readonly
name="{{newVariablesAttribute.Steps}}">
{{stepname}}
(I guess newVariablesAttribute.Steps are some array of objects. )