Angular 2 dialog popup with text field input - html

I have a simple popup that shows a message with OK button to release it, what I want is to add to this popup a text field that the user will need to type something in it and click OK to submit his answer.
currently it looks like this:
#Component({
selector: 'dialog-component',
template: `<h2>{{title}}</h2>
<p>{{message}}</p>
<button md-button (click)="dialog.close()">OK</button>`
})
export class DialogComponent {
public title: string;
public message: string;
constructor( public dialog: MdDialogRef<DialogComponent>) { }
}
and im using it like:
public showDialog(message: MessageBoxMessage) {
if (typeof message !== 'undefined') {
let dialogRef: MdDialogRef<DialogComponent> = this._dialog.open(DialogComponent);
dialogRef.componentInstance.title = message.title;
dialogRef.componentInstance.message = message.content;
}
}
how can I change it to have a popup with text-field and ok button tht pass me the value of the text-field?

You can create EventEmitter in your dialog:
#Component({
selector: 'dialog-component',
template: `<h2>{{title}}</h2>
<p>{{message}}</p>
<mat-form-field class="example-full-width">
<input matInput placeholder="Favorite food" #input>
</mat-form-field>
<button mat-button (click)="onOk.emit(input.value); dialog.close()">OK</button>`
})
export class DialogComponent {
public title: string;
public message: string;
onOk = new EventEmitter();
constructor( public dialog: MatDialogRef<ErrorDialogComponent>) { }
}
then subscribe to it in parent component
dialogRef.componentInstance.onOk.subscribe(result => {
this.resultFromDialog = result;
})
Plunker Example
Another way is passing value to MatDialog.close method
(click)="dialog.close(input.value)"
....
dialogRef.afterClosed().subscribe(result => {
this.resultFromDialog = result;
});
Plunker Example

You can bind the answer to a model like this :
#Component({
selector: 'dialog-component',
template: `<h2>{{title}}</h2>
<p>{{message}}</p>
<input type="text" name="data" [(ngModel)]="data">
<button md-button (click)="dialog.close()">OK</button>`
})
export class DialogComponent {
public title: string;
public message: string;
data: string;
constructor( public dialog: MdDialogRef<ErrorDialogComponent>) { }
}
And then bind the (click) to a function that sends your data.

Related

How To Add New Field in Existing JSON Object Using Angular 10

Hello I’m trying to add a new field (property) to existing json.db object based on a radio button click.
I think this is the best approach because the application has more than one product and some of them don’t have sizes and the other product are using the same model (product) I also don’t want to add a size because the sizes change based on the user clicking on a radio button s , m or l.
Products are being loaded to page from an api which works fine. The issue is when this particular product is added to cart it has to have a size. I am able to get the size value when clicking on one of the radio buttons. My cart component is not a parent or child of the product component
(product-item) to get the size value to be used in the cart I used a BehaviorSubject and I m able to get the size value. What I want to do is when the user click the radio for size and then click add to cart I need to add a field called size into cart object along with the value size to my existing json file.
Right now when add to cart it looks just like Product object. So my approach is to add to the object something like cart.size =sizeValue. object property value. I’m not sure how to accomplish this. Tried of couple of things with no luck. If someone can please point me in the right direction I would be so grateful.
Thanking You in Advance.
json file products object
"products": [
{
"id": 1,
"name": "Overalls",
"description": "Lorem Ipsum is simply dummy text of the printing and
typesetting industry. Lorem Ipsum has been the
industry's standard dummy text ever since the 1500s,
when an unknown printer took a galley of type and
scrambled it to make a type specimen book.",
"imageUrl": "http://localhost:4200/assets/overalls.png",
"price": 250
},
Product model
product.ts
export class Product {
id:number;
name: string;
size: string;
description: string;
price: number;
imageUrl: string;
constructor(id:number, name, description="", size:string, price=0,
imageUrl="" ){
this.id=id
this.name = name
this.description = description
this.price= price
this.size= size
this.imageUrl = imageUrl
}
}
Cart model
cart-item.ts
import { Product } from './product';
export class CartItem {
id: number;
productId: number;
productName: string;
qty: number;
price: number;
size:string;
imageUrl:string;
constructor(id:number, size, product:Product, qty= 1) {
this.id = id;
this.productId = product.id;
this.price = product.price;
this.size = size;
this.productName = product.name;
this.qty = qty;
this.imageUrl = product.imageUrl;
}
}
appservice uses Behavior Subject
appservice.ts
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
#Injectable({
providedIn: 'root'
})
export class AppserviceService {
private data = new BehaviorSubject('');
currentData = this.data.asObservable()
constructor() {
}
updateMessage(item:any){
this.data.next(item);
}
}
cart service
cart.service.ts
#Injectable({
providedIn: 'root'
})
export class CartService {
id: number;
product: any
cartUrl = 'http://localhost:4000/cart';
constructor(private http: HttpClient, private router: Router, private route: ActivatedRoute) {
}
//To do mapping the obtained results out to card items props pipe and mapp functions will be used.
//The observable returneded by carUrl is the source is going to pipe through the map projection anf get results of CartItem
getCartItems(): Observable<CartItem[]> {
return this.http.get<CartItem[]>(cartUrl).pipe(
map((result: any[]) => {
let cartItems: CartItem[] =[];
for(let item of result) {
cartItems.push( new CartItem(item.id, item.size, item.product, item.imageUrl ));
// localStorage.setItem('cartItems',JSON.stringify(cartItems));
sessionStorage.setItem('cartItems',JSON.stringify(cartItems));
}
return cartItems;
})
);
}
addProductToCart(product:Product):Observable<any>{
return this.http.post(cartUrl, {product});
}
}
Product component
product-item.ts
#Component({
selector: 'app-product-item',
templateUrl: './product-item.component.html',
styleUrls: ['./product-item.component.scss']
})
export class ProductItemComponent implements OnInit {
form: FormGroup;
submitted=false;
sizeBy:string;
Valuesize:string;
#Input() productItem:Product
#Input() addedToWishlist: boolean;
//#Input() addedToWishlistitem: boolean = false;
constructor(private msg: MessengerService, private cartService: CartService, private formBuilder: FormBuilder,
private wishlistService:WishlistService, private _wishlistitemService: WishlistItemService,private alertService: AlertService, private _data:AppserviceService) { }
ngOnInit() {
this.form = this.formBuilder.group({
sizeBy: ['', Validators.required]
});
}
// convenience getter for easy access to form fields
get f() { return this.form.controls; }
onSubmit() {
this.submitted = true;
// reset alerts on submit
this.alertService.clear();
// stop here if form is invalid
if (this.form.invalid) {
return;
}
if (!this.form.invalid){
this.Valuesize = this.form.value.sizeBy
this.shareData();
this.handleAddToCart();
}
}
handleAddToCart(){
this.cartService.addProductToCart(this.productItem).subscribe(() =>{
this.msg.sendMsg(this.productItem)
})
}
}
Cart component
cart.component.ts
#Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.scss']
})
export class CartComponent {
Valuesize:string;
#Input() product: CartItem;
#Input() cartItem: CartItem
cartItems = [
];
constructor(private msg: MessengerService, private cartService:CartService, private productService: ProductService, private formBuilder:FormBuilder, private _data:AppserviceService) { }
ngOnInit(): void {
this.handleSubscription();
this.loadCartItems();
this._data.currentData.subscribe(currentData => this.Valuesize = currentData)
}
handleSubscription(){
this.msg.getMsg().subscribe((product: Product) => { //This is an obsevable
this.loadCartItems();
})
}
loadCartItems(){
this.cartService.getCartItems().subscribe((items: CartItem[]) => {
this.cartItems = items;
})
}
}
HTML
product-item.component.html
<div class="col-sm-12">
<p class="float-left" style="text-align:left; margin-left:-2px;
width:140px;">{{productItem.name}}</p>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div class="float-left form-check" style="font-size:11px; text-
align:left; margin-left: -25px; width:200px">Size:
<alert></alert>
<label class="form-check-label checkbox-inline" for="sizeBy"
style="padding: 4px">
<input type="radio" name="sizeBy" formControlName="sizeBy"
id="small" [ngClass]=f.sizeBy value="S" required >
S</label>
<label class="form-check-label checkbox-inline" for="sizeBy" style="padding: 4px">
<input type="radio" name="sizeBy" formControlName="sizeBy" id="medium" [ngClass]=f.sizeBy value="M" required >
M</label>
<label class="form-check-label checkbox-inline" for="sizeBy" style="padding: 4px">
<input type="radio" name="sizeBy" formControlName="sizeBy" id="large" [ngClass]=f.sizeBy value="L" required>
L</label>
<div *ngIf="f.sizeBy.errors?.required"><b>You Must Coose A</b></div>
<div class="-flex justify-content-between align-items-left">
<div class="btn-group">
<button type="submit" style="border:0; outline:0; background-
color:transparent; padding-bottom: 100px; margin-left: -13px">
<img src="assets/shopping_cart_outline001.png" style="background-
color:none; color:#D30169; font-size:5px; cursor:pointer;
outline:none; outline:0; border:0"></button>
</div>
</div>
</div>
</form>

Angular innerHtml

I am relative new in Angular and I have the following question.
I have a component: my.component.html
<app-loading *ngIf="loading" message="Inhalt wird geladen..." delay="0"></app-loading>
<div [innerHtml]="content | safeHtml"></div>
And the following ts file: my.component.ts
export class MyComponent implements OnInit {
loading: boolean;
#Input() serviceUrl: string;
content: string;
constructor(public service: MyService) { }
ngOnInit() {
this.loading = true;
this.content = '';
this.service.getMyContent(this.serviceUrl).then(myContent => this.onMyContentRead(myContent));
}
onMyContentRead(dto: SimpleDto) {
this.loading = false;
this.content = dto.output;
}
}
It calls a REST service and gets the dto.output, which is a string contains the following html content from MyClassToShow.html
<li id="myBox_panels">
%s
<app-tooltip [myText]="test"></app-tooltip>
</li>
The tooltip components exists, and looks like this:
#Component({
selector: 'app-tooltip',
template: `
<a class="help" [pTooltip]="myText" [tooltipPosition]="tooltipPosition" </a>
})
export class TooltipComponent implements OnInit {
tooltipPosition: string;
#Input() myText;
constructor(private el: ElementRef) { }
ngOnInit() {
this.setTooltipPosition();
}
setTooltipPosition() {
....
}
It seems that the app-tooltip selector is not realized, because its template content is not displayed on the webpage, altough I can see the selector on the console log.
The innerHtml can only contain plain HTML code?
How can I get my app-tooltip template as well?
Thnak you a lot in advance!

Making a date field reactive in Angular

I'm trying to make a datepicker component from ngx-bootstrap a custom date-field, so that I can globalize some functionality and configs. But I can't seem to be able to catch the value of the Date object in the date input field.
My date-field.ts (I'm re-using some setup from a text-field. So bear with me if you see some remnants of the text field component. But I'm sure that my main problem is that my component doesn't know it's a date field)
import { Component, OnInit, forwardRef, Input } from '#angular/core';
import { FormControl, ControlValueAccessor, NG_VALUE_ACCESSOR } from '#angular/forms';
#Component({
selector: 'date-field',
templateUrl: './date-field.component.html',
styleUrls: ['./date-field.component.scss'],
providers:[
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => DateFieldComponent),
}
]
})
export class DateFieldComponent implements OnInit, ControlValueAccessor {
public dateField = new FormControl("")
private onChange: (name: string) => void;
private onTouched: () => void
#Input() name: string;
#Input() label: string;
#Input() required: boolean;
datepickerConfig = {
dateInputFormat: 'ddd, MMMM Do YYYY',
isAnimated: true,
adaptivePosition: true,
returnFocusToInput: true,
containerClass: 'theme-dark-blue'
}
constructor() { }
ngOnInit() { }
writeValue(obj: any): void {
const date = Date
this.dateField.setValue(new Date());
console.log(date);
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState?(isDisabled: boolean): void {
if (isDisabled) {
this.dateField.disable();
} else {
this.dateField.enable();
}
}
doInput() {
this.onChange(this.dateField.value)
}
doBlur() {
this.onTouched();
}
}
The template HTML:
<label
*ngIf="label"
for="{{name}}"
class="col-auto col-form-label {{required ? 'required' : '' }}">
{{label}}
</label>
<div class="col-expand relative">
<input
type="text"
class="form-control date-field"
#dp="bsDatepicker"
[formControl]="dateField"
(input)="doInput()"
(blur)="doBlur()"
ngModel
bsDatepicker
[bsConfig]="datepickerConfig"
required="{{required}}">
</div>
Using it in parent forms like this:
<date-field
name="dateChartered"
label="Date local union chartered"
formControlName="dateChartered"
required="true">
</date-field>
<p><strong>Date chartered is:</strong> {{dateChartered}}</p>
Assuming in your parent component you're correctly initializing FormGroup in controller and using it correctly in template, you have two main errors in your component.
First, as Belle Zaid says, you should remove ngModel from you custom datepicker's <input>.
Second, you are binding doInput() to (input), but it will fire only if you type in your input field, same for (change). You should bind to (bsValueChange) that's an output event exposed by BsDatepicker and it's safer, unless you plan to update value on user's input.
The resulting template will look like this:
<label *ngIf="label"
for="my-custom-datepicker"
class="col-auto col-form-label {{required ? 'required' : '' }}">
{{label}}
</label>
<div class="col-expand relative">
<input id="my-custom-datepicker"
type="text"
class="form-control date-field"
required="{{required}}"
bsDatepicker
[formControl]="dateField"
[bsConfig]="datepickerConfig"
(blur)="doBlur()"
(bsValueChange)="doInput()">
</div>
Once done the two changes you will notice an error in your console:
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was
checked. Previous value for 'ng-pristine': 'true'. Current value: 'false'.. Find more
at https://angular.io/errors/NG0100
This is due to the fact that calling this.dateField.setValue(obj) in writeValue will also trigger (bsValueChange) and, thus, doInput(). To overcome this issue, you can edit your code like the following:
private componentInit = false;
// ...
doInput() {
if (!this.componentInit) {
this.componentInit = true;
return;
}
this.onChange(this.dateField.value);
}

Angular error "Cannot read property 'firstName' of undefined"

Hi i am working on a search service to look for usernames in a elasticsearch database but i got the following error when i want to display the f.e. firstName of the user: Cannot read property 'firstName' of undefined.
I am working with Angular and Elasticsearch
service:
export class SearchService {
getElastic = 'http://34.62.28.281:9200/users/_doc/_search?q=';
private handleError: HandleError;
constructor(
private http: HttpClient,
httpErrorHandler: HttpErrorHandler) {
this.handleError = httpErrorHandler.createHandleError('TimelineService');
}
/** GET elasticsearch result */
getElasticResult( text: string ): Observable<User> {
this.http.get<User>(this.getElastic + text).subscribe(res => console.log(res));
return this.http.get<User>(this.getElastic + text, {responseType: 'json'});
}
EDIT:
The new HTML form:
<form [formGroup]="angForm2" *ngIf="user != null" (ngSubmit)="getUser()" class="form-inline my-5 my-lg-0">
<input id="searchText" name="searchText" class="form-control" type="string" placeholder="Search for user" aria-label="Post"
formControlName="searchText" required>
<p>{{user?.firstName}}</p>
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
the new component:
export class SearchServiceComponent implements OnInit {
user: User;
angForm2 = this.fb.group({
searchText: ['', Validators.required]
});
ngOnInit() {
this.getUser();
this.getObject();
}
constructor(private searchservice: SearchService, private fb: FormBuilder) { }
getUser() {
const userName = this.angForm2.value.searchText;
console.log(this.angForm2.value, userName);
this.searchservice.getElasticResult(userName).subscribe(user => (this.user = user));
}
getObject() {
return this.user;
}
}
Output of user and this.user:
User interface:
export interface User {
$oid: string;
firstName: string;
lastName: string;
username: string;
password: string;
follows: User[];
}
I guess getObject() is getting called when you load the form, by the time user is undefined so you are getting that error. why dont you just use user?.firstName since you already have the variable defined ?
<p>{{user?.firstName}}</p>
In your html you need to do something like this
<p>{{usersFirstName}}</p>
In your ts code, once you get the response from the server set this usersFirstName.
usersFirstName : string;
getUser() {
const userName = this.angForm2.value.searchText;
console.log(this.angForm2.value, userName);
this.searchservice.getElasticResult(userName).subscribe(user => (this.user = user)
this.usersFirstName = user.name;
);
}
1.SearchServiceComponent should implement OnInit class and implement its ngOnInit method
2. Call both the methods inside ngOnInit method sequentially
3. Check if this.user is not equal to null or undefined and handle it using ngIf condition
Answered by Sajitharan
Example for OnInit
TS
#Component({selector: 'my-cmp', template: `...`})
class MyComponent implements OnInit {
ngOnInit() {
this.getUser();
this.getObject()
}
getUser() {
const userName = this.angForm2.value.searchText;
console.log(this.angForm2.value, userName);
this.searchservice.getElasticResult(userName).subscribe(user => (this.user = user.hits.hits[0]._source));
}
getObject(){}
}

How to save text from input to variable in angular?

I'm trying to take text from one of my component.html files and save the input to a variable in a method in one of my .ts files. Can you help?
home.component.html file:
Username: <input ng-model="username"><br>
Password: <input ng-model="pass">
<button (click)="login()">Login</button>
home.component.ts file:
export class HomeComponent implements OnInit {
login()
{
const usr= {{username}};
const password={{pass}};
print("user is"+usr " Password is"+password);
}
}
If you are using angular it should be
ngModel instead of ng-model
Username: <input [(ngModel)]="username"><br>
Password: <input [(ngModel)]="pass">
and in component.ts
export class HomeComponent implements OnInit {
username : string;
password : string;
login()
{
const usr= this.username;
const password= this.password;
console.log("user is"+usr " Password is"+password);
}
}
you need to change ng-model to ngModel
ng-model :- angularjs
ngModel :- Angular 2 or greater
Html
Username: <input [(ngModel)]="username"><br>
Password: <input [(ngModel)]="pass">
<button (click)="login()">Login</button>
Component
export class HomeComponent implements OnInit {
public username: String;
public pass: String;
public function login() {
console.log('User Name: ' + this.username);
console.log('Password: ' + this.pass);
}
}