I am trying to dynamicaly create a sidenav from a remote JSON, which is working fine, it is getting the JSON from the URL and parsing it into a nav list. Now i want to console.log the selected nav list item, which i can't do, i looked up several solutions online but no use. Here is my code:
the service:
import 'rxjs/add/operator/map';
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Router } from '#angular/router';
interface Applications {
AUTO_ID: number;
REGISTARSKI_BROJ: string;
AUTO_TIP: string;
GODINA_PROIZVODNJE: string;
TIP_MOTORA: string;
BROJ_SASIJE: string;
SNAGA_HP: number;
KUPAC_ID: number;
}
#Injectable()
export class MenuService {
objectKeys = Object.keys;
private url = `MY_URL`;
public apps: Applications[];
constructor(public router: Router, protected http: HttpClient) { }
menu(e) {
e.preventDefault();
this.http.get(this.url).subscribe(result => {
this.apps = result as Applications[];
}, error => console.error(error));
}
ispisi(e) {
e.preventDefault();
console.log(this.apps); // WHEN I DO IT LIKE THIS, IT LOGS ALL OF THE OBJECTS TO THE CONSOLE
this.router.navigate(['table']);
}
}
HTML template:
<mat-sidenav-container>
<mat-sidenav #sidenav mode="push">
<mat-toolbar>
Glavni meni
</mat-toolbar>
<mat-nav-list>
<mat-list-item (click)="sidenav.toggle()" [routerLink]="['/']"><i class="material-icons">assessment</i>Dashboard</mat-list-item>
<mat-accordion>
<mat-expansion-panel (click)="menuService.menu($event)">
<mat-expansion-panel-header>
<mat-panel-title>
<i class="material-icons">directions_car</i>Automobili
</mat-panel-title>
</mat-expansion-panel-header>
<mat-nav-list *ngIf="menuService.apps">
<mat-list-item (click)="menuService.ispisi($event)" *ngFor="let app of menuService.apps">
{{app.REGISTARSKI_BROJ}}
</mat-list-item>
</mat-nav-list>
</mat-expansion-panel>
</mat-accordion>
</mat-nav-list>
</mat-sidenav>
<mat-toolbar color="primary">
<button mat-icon-button (click)="sidenav.toggle()">
<mat-icon>menu</mat-icon>
</button> Service stats
<span class="example-spacer"></span>
<button (click)="authService.logOut()" matTooltip="Izloguj se" matTooltipPosition="below" class="user" mat-icon-button>
<i class="material-icons">account_circle</i>
</button>
</mat-toolbar>
</mat-sidenav-container>
i am not sure i get what you are trying to do, but if you want the selected menu you should just change
<mat-list-item (click)="menuService.ispisi($event)" *ngFor="let app of menuService.apps">
{{app.REGISTARSKI_BROJ}}
</mat-list-item>
to something like this
<mat-list-item (click)="menuService.ispisi(app)" *ngFor="let app of menuService.apps">
{{app.REGISTARSKI_BROJ}}
</mat-list-item>
this way you will have access to the selected menu, and you can from there implement your selected logic
Related
in my app i display list of appeals, with their status (which is displayed using mat icon). Here is piece of my template
<div class="approve-detail" fxLayout="column" fxLayoutGap="10px">
<p>Created: {{absDetail?.reqDate|date:'d. L. y HH:mm'}}</p>
<ng-container *ngIf="absDetail?.defList">
<mat-list >
<mat-list-item class="def-item" *ngFor="let def of absDetail.defList">
<mat-icon matListIcon *ngIf="def.idReject!=0" class="warn" matTooltip="Rejected">thumb_down</mat-icon >
<mat-icon matListIcon *ngIf="def.idApprove!=0&&def.idReject==0" class="success" matTooltip="Approved">thumb_up</mat-icon>
<mat-icon matListIcon *ngIf="def.idReject==0 && def.idApprove==0" matTooltip="Waiting">help</mat-icon>
<p matLine>{{def.name}}</p>
</mat-list-item>
</mat-list>
<mat-list *ngIf="abs | isDeleteAppealed:absDetail.defList">
<mat-list-item class="def-item" *ngFor="let def of absDetail.defList">
<mat-icon matListIcon *ngIf="def.idCancel<0" color="warn" matTooltip="Rejected">thumb_down</mat-icon >
<mat-icon matListIcon *ngIf="def.idCancel>0" class="success" matTooltip="Approved">thumb_up</mat-icon>
<mat-icon matListIcon *ngIf="def.idCancel==0" matTooltip="waiting">help</mat-icon>
<p matLine>{{def.name}}</p>
</mat-list-item>
</mat-list>
</ng-container>
</div>
It works, but its kinda dirty with all that ng-ifs, is there any more elegant way to do this? I was thinking about pipe, but i need to generate three dynamic properties for each element: class, tooltip and proper icon name, so it doesnt seems like a better solution. Any ideas? What about some kind of directive?
One option you could do is wrap them in a separate component. Use your let def as an #Input() parameter. When it gets set, you can automatically change the value of the class/tooltip/icon. Something like this:
abs-icon.component.ts
imports...
#Component({
selector: 'abs-icon',
templateUrl: './abs-icon.component.html',
styleUrls: ['./abs-icon.component.css']
})
export class AbsIconComponent implements OnInit {
public cls: string;
public tooltip: string;
public icont: string;
private _abs: any;
get abs(): any{
return this._abs;
}
#Input() set abs(value: any) {
this._abs = value;
if (_abs.idReject != 0) {
cls = "warn";
tooltip = "Rejected";
icont = "thumb_down"
}
else if (.......do the rest){
/* some code */
}
}
constructor() { }
ngOnInit(): void { }
}
abs-icon.component.html
<mat-icon matListIcon
class="{{cls}}"
[matTooltip]="tooltip">
{{icon}}
</mat-icon >
using it:
<abs-icon [abs]="def"> </abs-icon>
I'm using Angular 9, where I want to dynamically change data of a menu item when a person logs in. But instead, since the menu gets loaded along with the home page, when a person logs in, the data change is not reflected in the menu items until I refresh the page manually. I tried using Renderer 2, ChangeDetectorRef and ElementRef but failded to reload the menu automatically. Below I'm adding just the relevant elements since the actual component code is long. Ask me if you need to know anything else:
Html:
<div class="widget-text">
<a mat-button [matMenuTriggerFor]="accountMenu" #accountMenuTrigger="matMenuTrigger" *ngIf="!isLoggedIn">
<mat-icon>person</mat-icon>
<span fxShow="false" fxShow.gt-sm class="flag-menu-title">Account</span>
<mat-icon class="mat-icon-sm caret cur-icon">arrow_drop_down</mat-icon>
</a>
<mat-menu #accountMenu="matMenu" [overlapTrigger]="false" xPosition="before" class="app-dropdown">
<span>
<button mat-menu-item [routerLink]="['/admin/login']" routerLinkActive="router-link-active">
<mat-icon >person</mat-icon>
<span>Login</span>
</button>
<button mat-menu-item [routerLink]="['/admin/login']" routerLinkActive="router-link-active">
<mat-icon>person_add</mat-icon>
<span>Register</span>
</button>
</span>
</mat-menu>
<a mat-button [matMenuTriggerFor]="profileMenu" #profileMenuTrigger="matMenuTrigger" *ngIf="isLoggedIn">
<mat-icon>person</mat-icon>
<span fxShow="false" fxShow.gt-sm class="flag-menu-title">Howdy, {{name}}</span>
<mat-icon class="mat-icon-sm caret cur-icon">arrow_drop_down</mat-icon>
</a>
<mat-menu #profileMenu="matMenu" [overlapTrigger]="false" xPosition="before" class="app-dropdown">
<span>
<button mat-menu-item [routerLink]="['/admin/profile']" routerLinkActive="router-link-active">
<mat-icon >person</mat-icon>
<span>Profile</span>
</button>
<button mat-menu-item (click)="logout()">
<mat-icon>warning</mat-icon>
<span>Logout</span>
</button>
</span>
</mat-menu>
</div>
typescript:
public name;
public isLoggedIn = false;
constructor(public router: Router, private cartService: CartService, public sidenavMenuService:SidebarMenuService) {
this.checkLogin();
this.name = Cookie.get('userName');
}
public checkLogin(): any {
if(Cookie.get('authtoken')) {
this.isLoggedIn = true;
}
}
You don't need to make things complicated, when you logged in your logged in guard (i.e. auth guard).
import { Injectable } from '#angular/core';
import { Router, CanActivate } from '#angular/router';
import { AuthService } from './auth.service';
#Injectable()
export class AuthGuardService implements CanActivate {
constructor(public auth: AuthService, public router: Router , private sideMenuService: SideMenuService) {}
canActivate(): boolean {
if (!this.auth.isAuthenticated()) {
this.sideMenuService.sideMenuData.next({...data}); // so here you can dispatch the side menu service data .
this.router.navigate(['dashboard']); // here after authentication it
will redirect to your dashboard
page
return false;
}
return true;
}
}
}
so after redirect when you land on the Dashboard Page , in the Dashboard component you have also inject the sideMenu Service and subscribe the BehaviourSubject menu data field .
public name;
public isLoggedIn = false; // here you don't need to check login
// because you come here from auth guard
constructor(public router: Router, private cartService: CartService,
public sidenavMenuService: SidebarMenuService) {
this.checkLogin(); // same no need to check login in each
component if you use auth guard
this.name = Cookie.get('userName');
}
public ngOnInit(){
this.sideMenuService.sideMenuData.subscribe((data)=>{
// hered you get the data dynamic , you can assign to any
// component field.
});
}
public checkLogin(): any {
if(Cookie.get('authtoken')) {
this.isLoggedIn = true;
}
}
so that's how whenever you login every time you dispatch some dynamic data and your behaviourSubject will get updated and where ever you subscribe like in Dashboard component you will get the dynamic data.
Hope it will help.
The constructor is executed only one time during the creation of the page.
constructor(public router: Router, private cartService: CartService, public sidenavMenuService:SidebarMenuService) {
this.checkLogin();
this.name = Cookie.get('userName');
}
Now, according to the code, if the cookie authtoken is not found during the construction, there is no way your app to know if that was created by another (login) process.
You should call the checkLogin function and the name assignment right after your login cocmpletes.
I have a page in which I have a Run button.If I click on Run button a dialog box appears with two options Yes and No.If a user clicks Yes I want to display a mat-progress bar.
I am confused as to where to write the html code of mat-progress bar and where to call it from.
HTML Code:
<mat-toolbar>
<div class="col-md-offset-11">
<button
mat-raised-button
mat-hint="Execute Query on Whole DataSet"
color="primary"
(click)="executeOnFullData()"
>
Run
</button>
</div>
</mat-toolbar>
TypeScript Code:
executeOnFullData() {
const dialogRef = this.dialog.open(ConfirmJobRunComponent, {
});
dialogRef.afterClosed()
}
HTML Code for dialogBox:
<div class="card">
<div class="card-header"><h5 class="title">Confirm</h5></div>
<div class="content">
<h3 mat-dialog-title>
Are you sure you want to run Recommendation Settings on the entire
Dataset?
</h3>
<div mat-dialog-actions>
<button
mat-button
[mat-dialog-close]="true"
(click)="confirmSelection()"
>
Yes
</button>
<button mat-button (click)="onNoClick()">
Cancel
</button>
</div>
</div>
Typescript Code for DialogComponent
import { MAT_DIALOG_DATA, MatDialogRef } from "#angular/material";
import { Component, Inject } from "#angular/core";
import { RecommendationService } from "../../recommendation-
service.service";
#Component({
selector: "app-confirm-job-run",
templateUrl: "./confirm-job-run.component.html",
styleUrls: ["./confirm-job-run.component.scss"]
})
export class ConfirmJobRunComponent {
constructor(
public dialogRef: MatDialogRef<ConfirmJobRunComponent>,
#Inject(MAT_DIALOG_DATA) public data: any,
public dataService: RecommendationService
) {}
onNoClick(): void {
this.dialogRef.close();
}
confirmSelection(): void {}
}
You can just subscribe to afterClosed of your dialogRef and based on the result you get back from your dialog (clicking Yes returns true, clicking No returns false) you can then show a mat-progress and execute your business logic.
Here
is a stackblitz showing how this could look like. The mat-progress
is currently indeterminate and not waiting for something to complete,
that is up to you.
Template (in your component where the button is located)
<mat-progress-bar *ngIf="showMatProgress" mode="indeterminate"></mat-progress-bar>
Component for above template
showMatProgress: boolean = false;
executeOnFullData() {
const dialogRef = this.dialog.open(ConfirmJobRunComponent, {});
dialogRef.afterClosed().subscribe((result) => {
this.showMatProgress = result;
});
}
An in your dialog component
onNoClick(): void {
this.dialogRef.close(false);
}
confirmSelection(): void {
this.dialogRef.close(true);
}
I am making the CURD API of .net core and Try to Use that API in Angular 2 application
1)Service File EmployeeService.ts
import { Injectable } from '#angular/core';
import { Http, Response, RequestOptions, Headers } from '#angular/http';
import 'rxjs/Rx';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { employee } from "../employee/emp"
#Injectable()
export class empservice {
//step 1: Add url of the .net api (get that by running .net api using F5)
private _url: string = "http://localhost:65088/api/Employee";
constructor(private _http: Http) { }
//step 2 : Method to get value from url
GetAllEmployee(): Observable<employee[]> {
return this._http.get(this._url).map((res: Response) => { return
<employee[]>res.json() });;
}
}
2)Component File Employee.Component.ts
import { Component, Input } from '#angular/core';
import { RouterModule, Router, ActivatedRoute, Data } from '#angular/router';
import { empservice } from './emp.service';
#Component({
selector: 'my-emp',
templateUrl: 'app/employee/Emp.html',
styleUrls: ['app/CSS/stylesheet.css', 'app/CSS/media.css'],
})
export class Employee {
public employee: employee[];
public ngOnInit() {
this.AllEmployee();
$(document).ready(function () {
$('#emptble').DataTable();
});
}
AllEmployee() {
this._employeeservice.GetAllEmployee().subscribe(empdata =>
this.employee = empdata);
}
}
export interface employee {
ID: any;
Fname: string;
Lname: string;
Age: any;
Mobile: any;
Phone: any;
}
3)HTML Code
<table>
<tr *ngFor="let emp of employee">
<td scope="row">{{emp.ID}}</td>
<td>{{emp.Fname}}</td>
<td>{{emp.Lname}}</td>
<td>{{emp.Age}}</td>
<td>{{emp.Mobile}}</td>
<td>{{emp.Phone}}</td>
<td>
<i style="cursor:pointer;" class="glyphicon glyphicon-edit
pointer"
(click)="Update(employee.ID)" title="Edit" data-
target="#update"></i>
<i style="cursor:pointer;" class="glyphicon glyphicon-trash
pointer"
(click)=" delete(employee.ID)" title="Delete">
</i>
<i style="cursor:pointer;" class="glyphicon glyphicon-user
pointer"
(click)="openModal(employee.ID)" title="Details" data-
target="#details"></i>
</td>
</tr>
</table>
I didn't get expected output of this code.
It's not show the employee name,id,age..etc Details of employee in the table cell.
API call is done correctly and data come from API to angular but i can't understand why that data not bind with angular html page.
You don't seem to call your AllEmployee() method at all, so no API call seems to be made.
Instead you should put this in the ngOnInit() lifecycle hook.
export class Employee implements OnInit {
public employee: employee[];
ngOnInit() {
this._employeeservice.GetAllEmployee()
.subscribe((data) => this.employee = <employee[]>data);
}
Side note: You're still using the Http service which was deprecated in version 4.3. You should switch to the new HttpClient.
You should use ngOnInit() lifecycle hook
ngOnInit() {
//call here in your data binding method
}
Transfer single item from a list item to cart list.
I am developing an Angular web app and want that when I click a button the single item of an array gets transferred from one service to another service and is also transferred on another component. I have successfully implemented it with a transfer of whole array but I am facing problem with a single item.Please help.
What I want is that when I click on Add to cart button the list item which is clicked only gets transferred and not the array of list items.
buyGame.html file
<div class="col-xs-6">
<a class="list-group-item clearfix" style="background-color:rgb(3, 0, 48)" *ngFor="let buying of buy">
<div class="pull-left" style="max-width:330px">
<h5 style="color:white">{{buying.names}}</h5>
<p style="color:white">{{buying.desc}}</p>
<button class="btn btn-danger ; pull-left" (click)= "onAddToCart()">Add To Cart</button>
</div>
<div>
<span class="pull-right">
<img [src]="buying.getImg" alt="image not loaded" class="img-responsive" style="max-height:100px">
</span>
</div>
</a>
</div>
buygame.service.ts file :
import { gameBuy } from "./buygame.model";
import { Injectable,EventEmitter } from "#angular/core";
import { cartService } from "./cart.service";
#Injectable()
export class gameService{
private gameServ: gameBuy[] = [
new gameBuy('batman','Batmobile and enhancements to signature features',"https://www.geek.com/wp-content/uploads/2016/02/batmans-625x352.jpg"),
new gameBuy('GTA 5',
"PlayStation 3 or Xbox 360 will be able to transfer their current Grand Theft Auto Online characters and progression to their choice of PlayStation 4 Xbox One or PC",
"http://onlysp.com/wp-content/uploads/2015/01/maxresdefault.jpg")
];
constructor(private cartSer: cartService){}
getBuyingList(){
return this.gameServ.slice();
}
addItemToCart(game:gameBuy[]){
this.cartSer.addItem(game);
}
}
buyGame.component.ts:
import { Component, OnInit,Input } from '#angular/core';
import { gameBuy } from '../shared/buygame.model';
import { gameService } from '../shared/buygame.service';
#Component({
selector: 'app-buy-game',
templateUrl: './buy-game.component.html',
styleUrls: ['./buy-game.component.css'],
})
export class BuyGameComponent implements OnInit {
#Input() buy:gameBuy[];
constructor(private service: gameService) { }
ngOnInit() {
this.buy = this.service.getBuyingList();
}
onAddToCart(){
this.service.addItemToCart(this.buy);
}
}
cart.component.ts:
import { Component, OnInit} from '#angular/core';
import { cartModel } from '../shared/cart.model';
import { cartService } from '../shared/cart.service';
import { gameBuy } from '../shared/buygame.model';
#Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.css'],
})
export class CartComponent implements OnInit {
cart:gameBuy[];
constructor(private service: cartService) { }
ngOnInit() {
this.cart = this.service.getCartItem();
}
}
cart.service.ts:
import { cartModel } from "./cart.model";
import { EventEmitter } from "#angular/core";
import { gameBuy } from "./buygame.model";
export class cartService{
cartChanged = new EventEmitter<gameBuy[]>();
private cart: gameBuy[] = [
new gameBuy('Batman','Batman is a cool game','https://images-na.ssl-images-amazon.com/images/I/91lu5KHSm3L._SY445_.jpg'),
new gameBuy('Gta 5','online game of GTA','https://www.rockstargames.com/V/img/global/order/mobile-cover.jpg')
];
getCartItem(){
return this.cart.slice();
}
addItem(cart:gameBuy[]){
this.cart.push(...cart);
this.cartChanged.emit(this.cart.slice());
}
}
cart.model.ts:
export class cartModel{
constructor(public cartName: string,public cartDesc: string,public cartImage:string){}
}
buygame.model.ts:
export class gameBuy{
constructor(public names:string, public desc:string, public getImg:string){}
}
You need to specify exact item you want to be added to the cart in the temlate:
(click)= "onAddToCart(buying)"
And then pass it right to your service as onAddToCart method parameter:
onAddToCart(buying: gameBuy){
this.service.addItemToCart(buying);
}
Also, your buygame service method should accept a single item, not a list:
addItemToCart(game: gameBuy){
this.cartSer.addItem(game);
}
Atl last, cart service should be updated too (just to push a single item)
addItem(cart:gameBuy){
this.cart.push(cart);
this.cartChanged.emit([...this.cart]); // slice() is ok too if you need a copy
}
Try providing the index in your call (click)= "onAddToCart(index)" and get it from your array.
OR provide the single object in (click)= "onAddToCart(buying)"
then receive it on TS