I have a parent component as under and 4 child components for registration. The data is not visible if i retrun from step L2 to L1.
Any idea?
<div class="container-fluid page-content" mat-dialog-content>
<div class="row">
<ul class="nav nav-pills nav-justified">
<li [ngClass]="{'active': this.actL1}"><a (click)="onClick('l1')" data-toggle="pill">L1</a></li>
<li [ngClass]="{'active': this.actL2}"><a (click)="onClick('l2')" data-toggle="pill">L2</a>
</li>
<li [ngClass]="{'active': this.actL3}"><a (click)="onClick('l3')" data-toggle="pill">L3</a>
</li>
<li [ngClass]="{'active': this.actL4}"><a (click)="onClick('l4')" data-toggle="pill">L4</a></li>
</ul>
<app-request-ltype *ngIf=actL1></app-request-ltype>
<app-request-ptype *ngIf=actL2></app-request-ptype>
<app-request-stype *ngIf=actL3></app-request-stype>
<app-request-rType *ngIf=actL4></app-request-rtype>
</div>
</div>
ltype component (RequestDetails ts file contains eg name:string)
import { Component, OnInit, getDebugNode } from '#angular/core';
import { FormGroup, FormBuilder } from '#angular/forms';
import { Router, ActivatedRoute } from '#angular/router';
import { RequestDetails } from '';
#Component({
selector: 'app-request-l1',
templateUrl: './request-l1.component.html',
styleUrls: ['./request-l1.component.css']
})
export class LtypeComponent implements OnInit {
requestL1Form: FormGroup;
constructor(private l1FormB: FormBuilder, private router: Router, private route: ActivatedRoute) {
this.requestL1Form = this.createL1FormGroup(l1FormB);
}
ngOnInit() {
}
createL1FormGroup(l1FB: FormBuilder) {
return l1FB.group({
l1Data: l1FB.group( new RequestDetails())
});
}
onSubmit() {
console.log('submitted values:', this.requestL1Form.value);
}
}
Related
I manage to fetch the product data through the URL and when I am on the product details page there is a button that allows me to add the product to a sub-collection of the logged in user.
Below is what I want:
users/{userID}/shopping/{productID}
details-product.component.html displaying information in product details
<div class="uk-container panier" *ngIf="product">
<div id="modal-center" class="uk-flex-top" uk-modal>
<div class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical">
<button class="uk-modal-close-default" type="button" uk-close></button>
<img [src]="(product | async)?.imageURL" class="nav-left">
</div>
</div>
<div class="uk-child-width-1-2#s" uk-grid>
<div>
<a href="#modal-center" uk-toggle>
<img [src]="(product | async)?.imageURL" class="nav-left" alt="">
</a>
</div>
<div>
<div class="uk-dark uk-padding">
<h3> {{ (product | async)?.name }}</h3>
<hr class="uk-divider-icon">
<div class="uk-flex prix">
<p class="uk-text">
<span>{{ (product | async)?.price | currency: 'XOF' }} </span>
</p>
</div>
<hr class="uk-divider-icon">
<button class="uk-button uk-button-default uk-form-width-medium" (click)="showDialog()">
<i class='bx bxs-cart-add'></i>
J'achète le produit
</button>
</div>
</div>
</div>
</div>
shopping-cart.service.ts
import { AngularFirestore, AngularFirestoreCollection } from '#angular/fire/compat/firestore';
import "firebase/auth";
import { User } from 'src/app/models/user.model';
import { Product } from 'src/app/models/product.model';
#Injectable({
providedIn: 'root'
})
export class ShoppingCardService {
userCollection: AngularFirestoreCollection<User>;
productsCollection: AngularFirestoreCollection<Product>;
constructor(private readonly dbstore: AngularFirestore) {
this.userCollection = this.dbstore.collection('users');
this.productsCollection = this.dbstore.collection('products');
}
addToMyCart(product: Product, userID: string, qteProduct: number) {
const userDoc = this.dbstore.firestore.collection('users').doc(userID);
const productDoc = this.dbstore.firestore.collection('products').doc(product.id);
const userShoppingProduct = userDoc.collection('shopping');
return userShoppingProduct.doc(product.id).set(product);
}
}
product.service.ts
import { Injectable } from '#angular/core';
import { AngularFirestore, AngularFirestoreCollection } from '#angular/fire/compat/firestore';
import { Router } from '#angular/router';
import { Observable } from 'rxjs';
import { Product } from 'src/app/models/product.model';
#Injectable({
providedIn: 'root'
})
export class ProductsService {
productCollection: AngularFirestoreCollection<Product>;
constructor(private dbstore: AngularFirestore, private router: Router) {
this.productCollection = this.dbstore.collection('products', (ref) =>
ref.orderBy('category', 'desc')
);
}
getDetailProduct(productId: string): Observable<any> {
return this.productCollection.doc(productId).valueChanges();
}
}
details-product.component.ts
import { ActivatedRoute } from '#angular/router';
import { Observable } from 'rxjs/internal/Observable';
import { User } from 'src/app/models/user.model';
import { Product } from 'src/app/models/product.model';
import { ProductsService } from '../../shared/services/products.service';
import { ShoppingCardService } from 'src/app/shared/services/shopping-card.service';
import { AngularFirestoreCollection } from '#angular/fire/compat/firestore';
import { AddToCartComponent } from './add-to-cart.component'
import { MatDialog } from '#angular/material/dialog';
#Component({
selector: 'app-details-product',
templateUrl: './details-product.component.html',
styleUrls: ['./details-product.component.css']
})
export class DetailsProductComponent implements OnInit {
quantity: number = 0;
productIdRoute: string;
isMyProduct: boolean = false;
product: Observable<Product>;
userCollection!: AngularFirestoreCollection<User>
constructor(
private route: ActivatedRoute,
private productService: ProductsService,
private shoppingCardService: ShoppingCardService,
private titleService: Title,
private dialog: MatDialog,
) {
const routeParams = this.route.snapshot.paramMap;
this.productIdRoute = String(routeParams.get('productId'));
this.product = this.productService.getDetailProduct(this.productIdRoute);
}
showDialog(): void {
const data = this.dialog.open(AddToCartComponent, {
width: '30rem',
data: { productID: this.productIdRoute },
});
console.log(data);
}
add-to-cart.component.ts
component in modal to confirm adding to cart
import { Component, OnInit, Inject } from '#angular/core';
import { MatDialog, MAT_DIALOG_DATA } from '#angular/material/dialog';
import { ShoppingCardService } from '../../shared/services/shopping-card.service';
import { Product } from 'src/app/models/product.model';
#Component({
selector: 'app-add-to-cart',
template: `
<div class="relative p-4 w-full max-w-md h-full md:h-auto">
<div class="p-6 text-center">
<svg aria-hidden="true" class="mx-auto mb-4 w-14 h-14 text-gray-400 dark:text-gray-200" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
<h3 class="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">Do you want to add this product?</h3>
<button (click)="onAddPubpik(data.product, data.userID)" type="button" class="text-white bg-gray-800 hover:bg-gray-800 focus:ring-4 focus:outline-none font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center mr-2">
Yes, i add to cart
</button>
</div>
</div>
`,
styleUrls: ['./details-product.component.css']
})
export class AddToCartComponent implements OnInit {
constructor(
#Inject(MAT_DIALOG_DATA) public data: { product: Product, userID: string, qteProduct: number },
private dialog: MatDialog,
private shoppingService: ShoppingCardService
) {}
ngOnInit(): void {
}
async onAddPubpik(product: Product, userID: string): Promise<void> {
this.dialog.closeAll();
const qteProduct = (product.quantity += 1);
product.isMyProduct = true;
await this.shoppingService.addToMyCart(product, userID, qteProduct);
}
}
When i confirm, in console :
On this line const qteProduct = (product.quantity += 1);, product is undefined. You’re not passing product to the matdialog component in your showDialog() method hence the error.
first of all thank you very much for taking the time to read this consultation. I'm new to angular development, I found it interesting to learn about this technology and not use the frameworks I've been using for some time. Currently I'm developing a very simple web application, the problem I have is that when I click on the "Login" link absolutely nothing happens. It also doesn't show me an error message. I copy the code that I currently have. I thank you if you could help me with this problem.
app.component.html
<nav class="navbar navbar-expand navbar-dark bg-dark fixed-top">
<div class="navbar-collapse collapse w-100 order-3 dual-collapse2">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link js-scroll-trigger" href="#">Inicio</a>
</li>
....
<li class="nav-item">
<!-- <a class="nav-link" [routerLink]="['/login']">Iniciar Sesión</a> -->
<a class="nav-link" routerLink="/login">Iniciar Sesión</a>
</li>
</ul>
</div>
</nav>
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { ReactiveFormsModule } from '#angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '#angular/common/http';
// used to create fake backend
import { fakeBackendProvider } from './_helpers';
import { appRoutingModule } from './app.routing';
import { JwtInterceptor, ErrorInterceptor } from './_helpers';
import { AppComponent } from './app.component';
import { HomeComponent } from './home';
import { LoginComponent } from './login';
import { RegisterComponent } from './register';
import { AlertComponent } from './_components';
#NgModule({
imports: [
BrowserModule,
ReactiveFormsModule,
HttpClientModule,
appRoutingModule
],
declarations: [
AppComponent,
HomeComponent,
LoginComponent,
AboutComponent,
TeamComponent,
ServiceProvidedComponent,
ContactComponent,
RegisterComponent,
AlertComponent
],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
// provider used to create fake backend
fakeBackendProvider
],
bootstrap: [AppComponent]
})
export class AppModule { };
app.components.ts
import { Component } from '#angular/core';
import { Router} from '#angular/router';
import { AuthenticationService } from './_services';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
currentUser: any;
constructor(private router: Router, private authenticationService: AuthenticationService) {
this.router.errorHandler = (error: any) => {
this.router.navigate(['404']); // or redirect to default route
};
this.authenticationService.currentUser.subscribe(x => this.currentUser = x);
}
logout() {
this.authenticationService.logout();
this.router.navigate(['/login']);
}
}
app.routing.ts
import { Routes, RouterModule } from '#angular/router';
import { HomeComponent } from './home';
import { LoginComponent } from './login';
import { RegisterComponent } from './register';
import { AuthGuard } from './_helpers';
const routes: Routes = [
// { path: '', component: HomeComponent, canActivate: [AuthGuard] },
{ path: '', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path: 'register', component: RegisterComponent },
// otherwise redirect to home
// { path: '**', redirectTo: '' }
];
export const appRoutingModule = RouterModule.forRoot(routes);
You need the <router-outlet></router-outlet> to show the rendered views.
So your code should be
<nav class="navbar navbar-expand navbar-dark bg-dark fixed-top">
<div class="navbar-collapse collapse w-100 order-3 dual-collapse2">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link js-scroll-trigger" href="#">Inicio</a>
</li>
....
<li class="nav-item">
<!-- <a class="nav-link" [routerLink]="['/login']">Iniciar Sesión</a> -->
<a class="nav-link" routerLink="/login">Iniciar Sesión</a>
</li>
</ul>
</div>
</nav>
<router-outlet></router-outlet>
I have a hamburger inside of my header - as soon as it is clicked, I wan't to disable scroll - since the hamburger is moving on scroll.
I tried to set the hamburger to position: fixed. But this one changed the position of its neighbour, which looked weird.
Is there a way to realize this in typescript - so that as soon clicked is true, scrolling is disabled. Or is there a better approach?
https://stackblitz.com/edit/angular-beiajz
export class HeaderComponent implements OnInit {
clicked = false;
onClick(): void {
this.clicked = !this.clicked;
}
constructor() { }
ngOnInit(): void {
}
}
<div class="container-fluid mobile position-absolute">
<div class="row m-0 w-100">
<div class="col-6 offset-3 justify-content-center d-flex">
<a class="align-self-center" routerLink="">
<h1>NØREBRO STUDIOS</h1>
</a>
</div>
<div class="col-3">
<button class="hamburger hamburger--collapse" (click)="onClick()" [class.is-active]="clicked" type="button">
<span class="hamburger-box">
<span class="hamburger-inner"></span>
</span>
</button>
</div>
<div class="container-fluid position-fixed min-vh-100 px-0 slide-in" [class.get-active]="clicked">
</div>
</div>
</div>
One of the way is passing a event from the child to parent whenever click is made on the hamburger menu and changing the parent class CSS
in app.component.html
<app-test (hamburgerClick)="hamburgerClickEvent($event)"></app-test>
<div [ngClass]="{
'container-fluid-overlay': overlayFlag === true,
'container-fluid': overlayFlag === false }">
</div>
in app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
overlayFlag = false; // overlay flag..onload overlay is hidden
public hamburgerClickEvent(e:boolean):void{
this.overlayFlag= e;
}
}
in app.component.css
.container-fluid {
min-height: 200vh;
}
.container-fluid-overlay {
height: auto;
}
in test.component.ts
import { Component, OnInit , Output, EventEmitter} from '#angular/core';
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
#Output() hamburgerClick = new EventEmitter();//emitter
clicked = false;
onClick(): void {
this.clicked = !this.clicked;
this.hamburgerClick.emit(this.clicked); //emitting clicked event to parent
}
constructor() { }
ngOnInit(): void {
}
}
Hope it helps :)
I'm using Angular 5, and I wanted to press another button to get another button.
I do not know if I would have to use the ngIf, but I do not know how to identify the previous button.
example.ts
import { Component, OnInit } from '#angular/core';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';
#Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
heroes: Hero[];
constructor(private heroService: HeroService) { }
ngOnInit() {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes);
}
add(name: string): void {
name = name.trim();
if (!name) { return; }
this.heroService.addHero({ name } as Hero)
.subscribe(hero => {
this.heroes.push(hero);
});
}
delete(hero: Hero): void {
this.heroes = this.heroes.filter(h => h !== hero);
this.heroService.deleteHero(hero).subscribe();
}
}
example.html
<ul class="heroes">
<li *ngFor="let hero of heroes">
<a routerLink="/detail/{{hero.id}}">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</a>
<button class="delete" title="delete hero" (click)="delete(hero)">x</button>
</li>
</ul>
In your component.ts:
#Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
heroes: Hero[];
showSecondButton: boolean = false;
constructor(private heroService: HeroService) { }
ngOnInit() {
this.getHeroes();
}
delete(hero: Hero): void {
this.heroes = this.heroes.filter(h => h !== hero);
this.heroService.deleteHero(hero).subscribe();
this.showSecondButton = true;
}
}
In your html:
<ul class="heroes">
<li *ngFor="let hero of heroes">
<a routerLink="/detail/{{hero.id}}">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</a>
<button class="delete" title="delete hero" (click)="delete(hero)">x</button>
<button *ngIf="showSecondButton"> Your second button</button>
</li>
</ul>
so your best bet is to create two buttons within a div, then have a toggle that switches the button that is displayed.
Example:
<div>
<button *ngIf=!displaysecondbutton (click)='showsecondbutton()'>First Button Yo</button>
<button *ngIf=displaysecondbutton>SecondButtonYo</button>
</div>
typescript file;
displaysecondbutton = false;
showsecondbutton(){
this.displaysecondbutton = true;
}
To keep the code concise I would implement an if statement in your delete function:
public deleteConfirmed = false;
public confirmDelete = false;
delete(hero: Hero): void {
if (deleteConfirmed) {
confirmDelete = deleteConfirmed = false;
this.heroes = this.heroes.filter(h => h !== hero);
this.heroService.deleteHero(hero).subscribe();
}
else{
confirmDelete = true;
}
}
Then in your html:
<button class="delete" title="delete hero" (click)="delete(hero)">Delete</button>
<button *ngIf="confirmDelete" class="delete" title="delete hero" (click)="deleteConfirmed=true; delete(hero)">Confirm Deletion</button>
This way, you are always cycling the same function and just altering some states along the way.
I'm trying to use the dynamic component provided by #GünterZöchbauer here Angular 2 dynamic tabs with user-click chosen components to create rows and columns. So far I got successfully the rows added but still can't get the columns created inside the rows.
Here is my code:
DesignerModule
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { MaterializeModule } from '../../shared/materialize/materialize.module';
import { DesignerComponent } from './designer.component';
import { RowComponent } from './designer.component';
import { ColumnComponent } from './designer.component';
import { DynWrapperComponent } from './dyn-wrapper.component';
#NgModule({
imports: [
CommonModule,
MaterializeModule,
],
declarations: [
DesignerComponent,
DynWrapperComponent,
RowComponent,
ColumnComponent,
],
entryComponents: [
RowComponent,
ColumnComponent,
],
providers: [
]
})
export class DesignerModule {}
DynWrapperComponent
import { Component, Compiler, ViewContainerRef, ViewChild, Input, ElementRef,
ComponentRef, ComponentFactory, ComponentFactoryResolver} from '#angular/core'
import {BrowserModule} from '#angular/platform-browser'
// Helper component to add dynamic components
#Component({
moduleId: module.id,
selector: 'dcl-wrapper',
template: `<div #target></div>`
})
export class DynWrapperComponent {
#ViewChild('target', {read: ViewContainerRef}) target: any;
#Input() type: any;
cmpRef:ComponentRef<any>;
private isViewInitialized:boolean = false;
constructor(private componentFactoryResolver: ComponentFactoryResolver,
private compiler: Compiler,
private el: ElementRef) {}
updateComponent() {
if(!this.isViewInitialized) {
return;
}
if(this.cmpRef) {
this.cmpRef.destroy();
}
let factory = this.componentFactoryResolver.resolveComponentFactory(this.type);
//this.resolver.resolveComponent(this.type).then((factory:ComponentFactory<any>) => {
this.cmpRef = this.target.createComponent(factory)
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}
DesignerComponent
import { Component, ViewChild, ElementRef, ContentChildren } from '#angular/core';
#Component({
moduleId: module.id,
selector: 'my-row',
templateUrl: 'row.component.html',
styles: [
`.row:hover {
border: 3px dashed #880e4f ;
}
`
]
})
export class RowComponent {
colIndex: number = 0;
colList: Object[] = [];
addColumn() {
this.colList.splice(this.colIndex, 0, ColumnComponent);
this.colIndex++;
}
removeColumn(colIdx: number) {
this.colList.splice(colIdx, 1);
}
}
#Component({
moduleId: module.id,
selector: 'my-column',
templateUrl: 'column.component.html',
styles: [
`.col:hover {
border: 3px solid #304ffe;
}
`
]
})
export class ColumnComponent {
}
#Component({
moduleId: module.id,
selector: 'my-designer',
templateUrl: 'designer.component.html',
})
export class DesignerComponent {
#ViewChild('builder') builder:ElementRef;
elementIndex: number = 0;
list: Object[] = [];
ngAfterViewInit() {
}
addRow() {
this.list.splice(this.elementIndex, 0, RowComponent);
this.elementIndex++;
}
remove(idx: number) {
this.list.splice(idx, 1);
}
}
DesignerComponent.html
<div #builder class="row">
<div class="s1 teal lighten-2">
<p class="flow-text">teste do html builder</p>
<div *ngFor="let row of list; let idx = index" >
<p class="flow-text">Linha {{idx}}</p>
<dcl-wrapper [type]="row"></dcl-wrapper>
<a class="btn-floating btn-small waves-effect waves-light purple" (click)="remove(idx)"><i class="material-icons">remove</i></a>
</div>
</div>
</div>
<a class="btn-floating btn-large waves-effect waves-light red" (click)="addRow()"><i class="material-icons">add</i></a>
RowComponent.html
<div #row class="row">
<div class="s12 teal lighten-2">
<p class="flow-text">adicionando linha no html builder</p>
</div>
<div *ngFor="let col of colList; let colIndex = index">
<p>Column</p>
<dcl-wrapper [type]="col"></dcl-wrapper>
</div>
<a class="btn-floating btn-small waves-effect waves-light waves-teal" (click)="addColumn()"><i class="material-icons">view_column</i></a>
</div>
ColumnComponent.html
<div class="col s1 purple lighten-2">
<p class="flow-text">column added ....</p>
</div>
This approach is generating the following error:
Expression has changed after it was checked. Previous value:
'CD_INIT_VALUE'. Current value:
Did it anyone get this working as nested elements?
Thanks very much for the help!
Try to use ngAfterContentInit hook instead of ngAfterViewInit in your DynWrapperComponent:
dyn-wrapper.component.ts
ngAfterContentInit() {
this.isViewInitialized = true;
this.updateComponent();
}