Angular 4 SideNav does not display - html

I am trying to insert a Material Sidenav into my component. For some reason, when I try to insert a basic sidenav it does not show anything -- main content, button to trigger sidenav, nor side content. I have imported both { MatSidenavModule } and { MatButtonModule} . However, if I comment out the mat-sidenav portion of the code, then the button will appear, so I think it may be an issue with the way I am setting up mat-sidenav.
Here is my HTML code:
<!--product.component.html-->
<h2>Store Inventory</h2>
<div class = "products">
Remaining: {{displayRemain}}
Requested: {{displayRequest}}
{{title}}
Total: {{cartTotal}}
</div>
<div>
<mat-sidenav-container class="example-container">
<mat-sidenav #sidenav class="example-sidenav">
Sidenav opened!
</mat-sidenav>
<div class="example-sidenav-content">
<button type="button" mat-button (click)="sidenav.open()">
Open sidenav
</button>
</div>
</mat-sidenav-container>
</div>
Here is the corresponding product.component.ts file: (I took out some functions which I commented out in the HTML)
import { Component, OnInit } from '#angular/core';
import { Product } from '../product';
import { ProductService } from '../product.service';
import {element} from 'protractor';
#Component({
selector: 'app-products',
templateUrl: './products.component.html',
styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {
products: Product[];
displayRemain: number;
displayRequest: number;
title: string;
prevRemain: number;
cartTotal: number;
constructor(private productService: ProductService) {
}
ngOnInit() {
this.title = 'Not Hello';
this.displayRemain = 0;
this.displayRequest = 0;
this.prevRemain = 10;
this.cartTotal = 0;
this.getProducts();
}
EDIT: got the answer, I didn't install the angular material animation library. Leaving this up in case others have the same problem.

Try to use sidenav.toggle() instead sidenav.open()
Regards

Related

Sharing data between two pages upon clicking button Angular

Im trying to get the hero details to show on hero-details page upon clicking on the button but I cant seem to figure out how to make it work. When I click on the button Im able to show the details on hero-list page but if I try to reroute it using routerLink I cant get the data to show. Right now Im just using <app-hero-details [hero]="selectedHero" > so I can have the data display when the hero button is clicked. I guess it has something to do with this [hero]="selectedHero".
heroes-list.components.html
<h1>Hero List</h1>
<ul>
<!--Displays a list of hero names-->
<li *ngFor="let hero of heroes">
<button type="button" (click)="onSelect(hero)" [class.selected]="hero === selectedHero" >
<span class="name">{{hero.name}}</span >
</button>
</li>
</ul>
<!-- just used to test hero-details page routing -->
<!-- <p><a routerLink="/hero-details" routerLinkActive="active">Click here</a></p> -->
<!-- just used to test 404/wildcard page routing -->
<!-- <p><a routerLink="/fakeLink" routerLinkActive="active">Click here</a></p> -->
<!-- this will show the data on this page-->
<app-hero-details [hero]="selectedHero" ></app-hero-details>
heroes-list.component.ts
import { Component, OnInit } from '#angular/core';
import { BackendService } from '../services/backend.service';
import { Hero } from '../types/Hero';
#Component({
selector: 'app-heroes-list',
templateUrl: './heroes-list.component.html',
styleUrls: ['./heroes-list.component.css']
})
export class HeroesListComponent implements OnInit {
selectedHero?: Hero;
heroes: Hero[] = [
];
onSelect(hero: Hero): void {
this.selectedHero = hero;
}
constructor(private backend: BackendService) { }
async ngOnInit(): Promise<void> {
// Gets a list of heroes to display
this.heroes = await this.backend.getHeroes();
}
}
hero-details.components.html
<p>Hero Details section</p>
<!-- <p><a routerLink="" routerLinkActive="active">Click here to go back to Hero List</a></p>
<h1>Hero Details page</h1> -->
<div *ngIf="hero" >
<!-- the hero details that will be displayed upon clicking on name -->
<h2 >{{hero.name | uppercase}} Details</h2>
<div><span>Id: </span>{{hero.id}}</div>
<div><span>Level: </span>{{hero.level}}</div>
<div><span>Class: </span>{{hero.class}}</div>
</div>
hero-details.components.ts
import { Component, Input, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router'
import { Hero } from '../types/Hero';
#Component({
selector: 'app-hero-details',
templateUrl: './hero-details.component.html',
styleUrls: ['./hero-details.component.css']
})
export class HeroDetailsComponent implements OnInit {
#Input() hero: Hero | undefined;
constructor(
private route: ActivatedRoute,
) { }
ngOnInit(): void {
}
}
Does your backend return anything? Show us the backend and show what it is returning. Also I would advise to refactor ngOnInit() to not be async function. Refactor logic away from ngOnInit to a new function and have ngOnInit call out the said new function.
Otherwise it looks like it should work.
ngOnInit(): void {
this.getHeroes();
}
async getHeroes() {
// Gets a list of heroes to display
this.heroes = await this.backend.getHeroes();
}
Example: https://stackblitz.com/edit/heroes-list-fjdq6g?file=src%2Fapp%2Fheroes%2Fheroes.component.ts

How to make the creation of a card dynamic?

My Problem is that every template created will be Added to the same Card like the image below shows it
And if i set the height rather than auto it will cut the card until the giving measurement.
is there anyone who can help me to make each template have it own card ?
Card.Html
<div class="content" >
<div fxLayout="row wrap" fxLayoutGap="16px grid">
<div [fxFlex]="(100/gridColumns) + '%'" fxFlex.xs="100%" fxFlex.sm="33%" >
<mat-card class="mat-elevation-z4 info" >
<mat-card-content *ngFor="let item of templates" [innerHTML]="item.templatebody | safeTemplate"></mat-card-content> <!-- named one way flow syntax property binding-->
</mat-card>
</div>
</div>
</div>
Card.ts
import { Component, OnInit, ViewChild,Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from "#angular/platform-browser";
import { EmailEditorComponent } from 'angular-email-editor';
import { SenderService } from "../sender.service";
import { TemplateCard } from "src/app/layouts/default/templates/template";
//this pipe is designed to make the HtmlRender Safe using SanitizerDOM
#Pipe({ name: "safeTemplate" })
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(value: any) {
return this.sanitizer.bypassSecurityTrustHtml(value);
}
}
#Component({
selector: 'app-cards',
templateUrl: './cards.component.html',
styleUrls: ['./cards.component.scss']
})
export class CardsComponent implements OnInit {
public templates:TemplateCard[];
public model: any;
options = {
};
gridColumns = 3;
toggleGridColumns() {
this.gridColumns = this.gridColumns === 3 ? 4 : 3;
}
dangerousUrl='<input type="checkbox">';
constructor(public http:SenderService) { }
ngOnInit(): void {
this.model=this.http.getEmail("http://localhost:3000/savetemplate").subscribe( data => {
this.templates=data;
console.log(this.templates);
},
err => console.error(err),
() => console.log('template completed')
);}
}

How can I route from a component to a section of another component in Angular?

I have two components and they are situtated in the different routes. In the Second component There is a div. I want to route from first component to the div of the second component. Yes, It is simple to route the second component. But I want to scroll be top of the div.
Thank you for answers.
This tag is declared in component1
<a [routerLink] = "['/c2']" fragment="c2id"> Link </a>
Here are the component2 changes
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-c2',
templateUrl: './c2.component.html',
styleUrls: ['./c2.component.css']
})
export class C2Component implements OnInit {
private fragment: string;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.fragment.subscribe(fragment => {
this.fragment = fragment;
});
}
ngAfterViewInit(): void {
try {
document.querySelector('#' + this.fragment).scrollIntoView();
} catch (e) {}
}
}
And your component2 html will be like this
<p style="height: 800px;">
c2 works!
</p>
<hr>
<div id="c2id" style="height: 500px;">
The div with c2id
</div>
Here is the updated and working stackblitz
https://angular-fragment-example.stackblitz.io
I think you are looking for Fragments.
Official Docs : Angular Docs- Query Params and Fragments
Examples:
Manual Navigation
in c1.html
<a [routerLink] = "['/c2']" [fragment]="c2id"> Link </a>
in c2.html
<div id="c2id">content</div>
Programatic Navigation
in c1.ts
private fragmentSetDynamically: string;
constructor(private router: Router){}
onClickButton(){
this.router.navigate(['/c2'], {fragment: fragmentSetDynamically});
}
Getting the fragment :
in c2.ts
private fragment: string;
constructor(private activatedRoute: ActivatedRoute){}
ngOnInit(){
this.fragment = this.activatedRoute.snapshot.fragment;
}

Kind of recursive usage of an Component possible?

After searching for like two hours for a solution I decided to ask some pros suspecting the solution could be quite simple.
It is an Angular7 project.
I would like to have a "goal" in my goals component with a button "+". When you click that button I want to have annother goal being added to the page. So I want to click a button of the goal component to create a new goal, which is something like recursive to me.
goals.component.html:
<input type="text" value="Ich brauche einen Laptop für maximal 1000 Euro.">
<br/>
<br/>
<app-goal id="{{lastGivenId+1}}"></app-goal>
goals.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-goals',
templateUrl: './goals.component.html',
styleUrls: ['./goals.component.scss']
})
export class GoalsComponent implements OnInit {
lastGivenId: number = 0;
constructor() { }
ngOnInit() {
}
}
goal.component.ts and goal.component.html:
//Typescript code
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-goal',
templateUrl: './goal.component.html',
styleUrls: ['./goal.component.scss']
})
export class GoalComponent implements OnInit {
#Input() id : number;
constructor() { }
ngOnInit() {
}
onAddLowerGoal(currentGoalID:number){
// var goalElement = document.registerElement('app-goal');
// document.body.appendChild(new goalElement());
let newGoal = document.createElement("app-goal");
newGoal.setAttribute("id", "999");
let currentGoal = document.getElementById(currentGoalID.toString());
document.body.insertBefore(newGoal, currentGoal);
}
}
<html>
<div id="{{id}}" class="goal">goal{{id}}</div>
<button id="AddLowerGoal1" (click)="onAddLowerGoal(999)">+</button>
</html>
This way, it creates an app-goal element, but the div and button elements within the app-goal element is missing.
How can this problem be solved? Any help is welcome. Thanks in advance.
First glance: delete the html tags from your goal.component.html file.
Next: you can recursively add app-goal using angular. Inserting app-goal element the javascript way only adds the <app-goal></app-goal> object. It doesn't create an angular component. It doesn't bind your data.
Also if you're using Angular's #Input, you need to assign a component input with square braces. Do not use tags.
goals.component.html:
<input type="text" value="Ich brauche einen Laptop für maximal 1000 Euro.">
<br/>
<br/>
<app-goal [id]="lastGivenId+1"></app-goal>
goal.component.html:
<div id="{{id}}" class="goal">goal{{id}}</div>
<button id="AddLowerGoal1" (click)="onAddLowerGoal(999)">+</button>
<div *ngFor="let subGoal of subGoals">
<app-goal [id]="subGoal.id"></app-goal>
</div>
goal.component.ts:
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-goal',
templateUrl: './goal.component.html',
styleUrls: ['./goal.component.scss']
})
export class GoalComponent implements OnInit {
#Input() id : number;
subGoals: Array<any> = [];
constructor() { }
ngOnInit() { }
onAddLowerGoal(currentGoalID: number){
this.subGoals.push({id: currentGoalID});
}
}
You can also use a service to store your goals and subgoals to access them later.
I think what you're looking for is a Reactive Form with FormArray with dynamically added form controls.
Take a look at this for eg:
import { Component } from '#angular/core';
import { FormControl, FormGroup, FormArray, FormBuilder } from '#angular/forms';
#Component({...})
export class GoalsComponent {
goalsForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.goalsForm = this.fb.group({
goals: this.fb.array([])
});
}
onFormSubmit() {
console.log('Form Value: ', this.goalsForm.value);
}
get goals() {
return (<FormArray>this.goalsForm.get('goals')).controls;
}
addGoal() {
(<FormArray>this.goalsForm.get('goals')).push(this.fb.control(null));
}
}
And here's the template for this:
<h2>Goals:</h2>
<form [formGroup]="goalsForm" (submit)="onFormSubmit()">
<button type="button" (click)="addGoal()">Add Goal</button>
<hr>
<div *ngFor="let goal of goals; let i = index;" formArrayName="goals">
<div>
<label for="goal">Goal {{ i + 1 }}: </label>
<input type="text" id="goal" [formControlName]="i">
</div>
<br>
</div>
<hr>
<button>Submit Form</button>
</form>
Here's a Sample StackBlitz for your ref.

Angular - passing data in to component

I'm still somewhat new to Angular development.
I'm building a website for a construction company, where I'm using three different components on one page. Here's a basic outline of what the page currently has, and what I want it to do:
The projects component contains a list of projects on the right side
of the page. Out of all those projects, the one that is selected
shows up on the left side of the page (projectdetail.component.html)
The user may click on any of the projects on the right side of the page to change the selected project. This new one will show up on the left side of the page in projectdetail.component.html
In the projectdetail component, there is a mini gallery of other
images that the user can click on in order to change the main image
that displays (like a typical photo slideshow).
THE PROBLEM I'M HAVING RIGHT NOW: The main image in projectdetail.component no longer changes whenever I click on any of the projects in the right panel (all of the other data, including the address, images in the slideshow, etc. do update as they should); they only time it changes is when I click on any of the images in the gallery in the projectdetail component. A solution I've proposed is to try to make updates to 'mainImage' (See code below) whenever you click on a project on the right panel, which it does not do. I am not sure how to accomplish this.
My Project class:
export class Project {
id: number;
address: string;
images: string[];
price: string;
featured: boolean;
description: string;
}
My Project Service:
import { Injectable } from '#angular/core';
import { Project } from '../shared/project';
import { PROJECTS } from '../shared/projects';
#Injectable()
export class ProjectService {
constructor() { }
getProjects(): Project[] {
return PROJECTS;
}
getProject(id: number): Project {
return PROJECTS.filter((project) => (project.id === id))[0];
}
}
Not including one of the components, which is irrelevant to the question, they are as follows:
projects.component.html
<div class="container"
fxLayout.sm="row"
fxLayout.xs="column">
<div fxFlex=60>
<app-projectdetail [project]="selectedProject" ></app-projectdetail>
</div>
<div fxFlex=40 *ngIf="projects">
<mat-grid-list cols="1" rowHeight="300px">
<mat-grid-tile *ngFor="let project of projects" (click)="onSelect(project)">
<img src="{{ project.images[0] }}">
<mat-grid-tile-footer>
<h1 mat-line ngDefaultControl>{{ project.address | uppercase }}</h1>
</mat-grid-tile-footer>
</mat-grid-tile>
</mat-grid-list>
</div>
</div>
projects.component.ts
import { Component, OnInit, Inject, Optional } from '#angular/core';
import { MatDialog } from '#angular/material';
import { ProjectDialogComponent } from '../project-dialog/project-dialog.component';
import { Project } from '../shared/project';
import { ProjectService } from '../services/project.service';
#Component({
selector: 'app-projects',
templateUrl: './projects.component.html',
styleUrls: ['./projects.component.scss']
})
export class ProjectsComponent implements OnInit {
projects: Project[];
selectedProject: Project;
image: String;
mainImage: String;
constructor(private projectService: ProjectService, private dialog: MatDialog) { }
ngOnInit() {
this.projects = this.projectService.getProjects();
this.selectedProject = this.projectService.getProject(0);
}
onSelect(project: Project) {
this.selectedProject = project;
this.mainImage = project.images[0];
}
}
projectdetail.component.html
<div class="container"
fxLayout="row"
fxLayoutGap="10px">
<div fxFlex=100>
<mat-card *ngIf="project">
<img src="{{ mainImage }}" (click)="openDialog(project)">
<mat-card-header>
<mat-card-title><h1>{{ project.address | uppercase }}</h1></mat-card-title>
</mat-card-header>
<div id="preWrapper">
<div id="imageWrapper">
<div id="imageContainer" *ngFor="let image of project.images">
<img src="{{ image }}" (click)="changeImage(image)" />
</div>
</div>
</div>
<mat-card-content>
<p>{{ project.description }}</p>
</mat-card-content>
</mat-card>
</div>
</div>
projectdetail.component.ts
import { Component, OnInit, Inject, Input } from '#angular/core';
import { MatDialog } from '#angular/material';
import { ProjectDialogComponent } from '../project-dialog/project-dialog.component';
import { Project } from '../shared/project';
import { ProjectService } from '../services/project.service';
#Component({
selector: 'app-projectdetail',
templateUrl: './projectdetail.component.html',
styleUrls: ['./projectdetail.component.scss']
})
export class ProjectdetailComponent implements OnInit {
#Input()
project: Project;
projects: Project[];
selectedProject: Project;
image: String;
mainImage: String;
constructor(private projectService: ProjectService, private dialog: MatDialog) { }
ngOnInit() {
this.mainImage = this.projectService.getProject(0).images[0];
}
openDialog(project: Project): void {
let dialogRef = this.dialog.open(ProjectDialogComponent, {
data: {
address: this.project.address,
images: this.project.images
}
})
}
changeImage(image: String) {
this.mainImage = image;
}
}
you write ngOnChange event in you detail component and then raise event for changing image in you main page ,
ngOnChanges(changes: SimpleChanges) {
for (let propName in changes) {
if (propName === 'project') {
Promise.resolve(null).then(() =>
{raise event or write code toc hange main page image});
}
}
}