<div id="home-container">
<div class="sidebar">
<button mat-raised-button [disabled]="true">This is a button</button>
</div>
<div class="main-panel">
<ac-map></ac-map>
</div>
</div>
Environment:
Angular 10
Chrome/Firefox (Incognito mode)
Hi guys,
I'm experiencing some undesirable behaviour when displaying my angular project. The above example shows a simple component with a button that is disabled by default (I'm using 'true' as a placeholder for a variable). When I load the component the button should be disabled. HOWEVER. When the component is loaded the button is enabled for the first second or two and then is disabled - making it look disorganised. How can I avoid this?
Kind regards,
Scott.
According to your requirement, I suggest you read the document about the component lifecycle of Angular. https://angular.io/guide/lifecycle-hooks
Please check this out for a live sample.
import { Component, OnInit } from "#angular/core";
/**
* #title Basic buttons
*/
#Component({
selector: "button-overview-example",
templateUrl: "button-overview-example.html",
styleUrls: ["button-overview-example.css"]
})
export class ButtonOverviewExample implements OnInit {
disabled = true;
toggle() {
this.disabled = !this.disabled;
}
ngOnInit(): void {
this.disabled = false;
}
}
https://stackblitz.com/edit/toggle-angular-material-button-sample?file=src/app/button-overview-example.html
In this sample, I used the variable disabled to indicate the button state, and implemented the OnInit hook which I change false to true.
Related
I have created this Angular 7 application where I'm trying to get the source of an image as follows:
<div *ngIf="showAllRec" class="pt-3">
<div *ngFor="let recommendation of allRecommendations">
<div class="row pt-2">
<div class="col-12">
<img [src]="generateProfilePictures()">
</div>
</div>
</div>
generateProfilePictures() {
const profiles = [
'../assets/profiles/dark-blue.png',
'../assets/profiles/dark-grey.png',
'../assets/profiles/light-blue.png',
'../assets/profiles/light-green.png',
'../assets/profiles/light-grey.png',
'../assets/profiles/light-red.png',
'../assets/profiles/medium-blue.png',
'../assets/profiles/medium-brown.png',
'../assets/profiles/medium-orange.png',
'../assets/profiles/medium-purple.png',
'../assets/profiles/medium-red.png',
'../assets/profiles/medium-yellow.png',
];
return profiles[Math.floor(Math.random() * profiles.length)];
}
The following results in an error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Any idea's why this is happening?
This Error occurs, because in development Angular will run Change detection twice to make sure while the first CD run was being done, components which are already checked by CD should not change values while CD run is in Progress.
In your case the method generateProfilePictures() acts as a getter for src property and every get called by CD gets a different value.
RT now i am on a mobile device, so it's hard for me to prepare a stackblitz be demo.
But you can delay this calculation either by catching the index you are generating randomly, or wrapping the function content in a settimeout/observable (still have to try, can't be sure on a cellphone )
Use ChangeDetectionStrategy.OnPush into your component.
import { Component, ChangeDetectionStrategy } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush //<====Add this property
})
Here is working stackblitz: ExpressionChangedAfterItHasBeenCheckedError Solved
I am trying to create a dropdown directive which I can use to add dropdowns to any DOM element. I wrote this directive:
import { Directive, HostListener } from '#angular/core';
#Directive({
selector: '[appDropdown]'
})
export class DropdownDirective {
constructor() { }
isOpen: boolean = false;
#HostListener('click') toggle() {
if (this.isOpen === true) {
this.hide();
} else {
this.show();
}
this.isOpen = !this.isOpen;
}
private show() {
// What to do here?
}
private hide() {
// What to do here?
}
}
This directive basically listens for a click on the DOM element it is applied to. When it registers a click I want to toggle the dropdown element that is in the same container as the element which I applied the directive to (by using the display property). My html code looks like this in a simplified form:
<a appDropdown>Dropdown</a>
<ul class="dropdown"> <--- How can I apply a display style property to this element when clicking the anchor (to hide/show the dropdown)?
<li><a>Option A</a></li>
<li><a>Option B</a></li>
</ul>
I read through the Angular docs carefully but it is not explained there.
I hope you get my problem. Thanks!
It's my understanding that this isn't the correct use for directives. I'm trying to achieve a very similar output.
I'm trying to implement something similar, and reading through the documentation (and #evandro-mendes' answer above), structural directives are designed to alter the behavior of the DOM, without defining any templates themselves (see angular docs).
Look at https://github.com/valor-software/ngx-bootstrap/blob/development/src/dropdown/bs-dropdown.directive.ts (or the docs/demo https://valor-software.com/ngx-bootstrap/#/dropdowns) and they are using a directive to show/hide/manipulate the component, but not to declare its own content.
My solution, using ngx-bootstrap is to create a component as follows:
dropdown.component.ts:
#Component({
selector: 'dropdown',
template: './dropdown.component.html'
})
export class AutosuggestComponent {
#Input() viewModel: string[];
#Input() isOpen: boolean = false;
}
dropdown.component.html
<div dropdown [isOpen]="isOpen" [autoClose]="true" placement="top">
<ng-content #input>
</ng-content>
<div *dropdownMenu class="dropdown-menu" role="menu">
<div *ngFor="let item of viewModel" class="dropdown-item">
{{item}}
</div>
</div>
usage
<dropdown [viewModel]="sourceData" [isOpen]="isDropdownOpen">
<input type="text">
</dropdown>
This way I don't define any custom behaviour, and can still use the dropdown for any input within the app.
Hope this helps :)
I think some Angular5 attribute should be included.
Please follow this link:
Building An Angular 5 Project with Bootstrap 4 and Firebase
I'm using Angular 2 with Ngrx and Angular Material.
Are all UI changes like dropdown or dialog supposed to be in store?
For example:
<button md-button [mdMenuTriggerFor]="menu">Menu</button>
<md-menu #menu="mdMenu">
<button md-menu-item>Item 1</button>
<button md-menu-item>Item 2</button>
</md-menu>
Should I support dropdown in the store?
Next example:
<md-sidenav-container class="example-container">
<md-sidenav #sidenav class="example-sidenav">
Jolly good!
</md-sidenav>
<div class="example-sidenav-content">
<button type="button" md-button (click)="sidenav.open()">
Open sidenav
</button>
</div>
</md-sidenav-container>
Can I use open method? Maybe I should create component that wrap sidenav in component that operate only on input Input() open;?
For me, there are generally 3 questions I ask.
Are the UI changes isolated to the component and do not affect other components?
Do the UI changes need to be persisted when the view returned to after have been destroyed?
For debugging purposes do you want to track this state (possibly in order to recreate the view of the end user?)
If you answered NO to these 3 questions then you probably do NOT need to put the state of that component in the store.
By not coupling something the store, you make it more modular, easier to test and reusable.
You should use the store to keep state and the UI should be bound to that state. You can then keep Observable to that state hierarchy or subscribe to those state changes and update the UI accordingly and dynamically.
This is what I had in mind:
import { Component } from "#angular/core";
import { Store } from "#ngrx/store";
// Other relevant imports ....
#Component({
selector: 'some-comp',
templateUrl: 'some-comp.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SomeComponent implements OnDestroy {
employeeObs$:Observable<EmployeeInfo>;
constructor( private store: Store<IAppState>) {
this.employeeObs$ = this.store.select('employee')
.map((next: IEmployeeState) => next.info);
}
// ...
}
And then on html template something like:
<!-- Some other regular DOM
...
...
-->
<!-- Conditional DOM based on state -->
<div *ngIf="employeeObs$ | async as employeeInfo">
<div type="text">{{employeeInfo.name}}</div>
</div>
<!-- Some other regular DOM
...
...
-->
The conditional tag will only show if Observable has data...
What I want to do
I want to create a reusable Angular 2 button component that may render as an <a /> tag or an <input /> tag depending on an input to the component called type. I want the button component to accept content children which will be rendered as the button label.
To illustrate: an Angular template that invokes my button component like so:<button>Hello</button> should render as <a>Hello</a> in the DOM. However, if a property type="submit" is set (e.g. <button type="submit>Hello</button>) then the output in the DOM should be <input type="submit">Hello</input>.
To further clarify, if I were using React I could create [an overly simplified version of] this component with:
const Button = ({ type, children }) =>
type === "submit"
? <input type="submit">{children}</input>
: <a>{children}</a>
Where I'm stuck
Creating an Angular component that displays content children using <ng-content /> was relatively straightforward. However, I'm yet unable to render those children inside a dynamically chosen tag - either <a /> or <input /> depending on the value of the type property.
What I've tried
I initially tried to use <ng-content /> inside an ngIf or ngSwitch directive, only to find out that <ng-content /> can appear at most once in any given template (unless it’s qualified with a selector). However, I want to output all content children so selectors are not helpful.
I keep finding references to DynamicComponentLoader, but that appears to be deprecated.
I've seen the ContentChildren decorator which would allow my button component to access the content children being passed to it, but I'm not sure how to then take those children and inject them into my component template.
I came across NgTemplateOutlet, which seems like it might help me switch between two entirely different templates (one w/ the <a /> tag and one with the <input /> tag). However that's marked as “Experimental” and I’m having trouble understanding the usage.
Any help would be greatly appreciated!!
#Component({
selector: 'adapting-button',
template: `
<a *ngIf="type !== "submit">{{value}}</a>
<input *ngIf="type === "submit" type="submit" [value]="value">
`,
})
export class AdaptingButtonComponent {
#Input() type: any;
#Input() value: any;
}
#Component({
selector: 'app-root',
templateUrl: `
<adapting-button [type]="'submit'" [value]="Hello"></adapting-button>
`,
})
export class AppComponent {
title = 'app works!';
}
I am developing an application using Angular2.
I have a component with the following template:
<div>
<router-outlet></router-outlet>
</div>
Can someone please help me how to load an external URL 'www.example.com' in this div?
Just create a component to render inside <ng-outlet> by using the routing config.
Then you component template inside should have an <iframe> pointing to your external site.
import {Component, OnInit} from '#angular/core';
#Component({
selector: 'app-external-page',
templateUrl: './external-page.component.html',
styleUrls: ['./external-page.component.css']
})
export class ExternalPageComponent implements OnInit {
title = 'app works!';
constructor(private _stellarService: StellarService) {
}
ngOnInit(): void {
}
}
Then your component template should look like
<div>
<iframe src="yourexternalpage url"></iframe>
</div>
Having a code like the one above, only remaining step if to configure a route in your routing.
did you get answer for this ?
You can have a component as mentioned here . Import and add it to your NgModule; After that import it in the page you want and use the selector instead of <router-outlet>.