I have a multiple charts in my page and I'm trying to make a delete call but some reason my chart UI is not updating immediately when I click the delete button. I always need to refresh the browser in order to see the changes.
I uploaded the full code for this two component her https://stackblitz.com/edit/angular-ivy-nnun96 so I would be really appreciated if I can get any suggestion on how to make the UI remove the Chart immediately when the user press Delete button.
Mc Chart List TS
deleteChart(){
this.chartService.deleteChart(this.chart.guid).subscribe((deleted) => {
console.log(deleted);
});
}
Mc Chart List HTML
<button mat-menu-item (click) = "deleteChart()" *ngIf = "chart.hasAccess && chart.canEdit && !chart.isPublished">Delete Chart</button>
Parent HTML
<mc-chart-list [chart]="chart" [editMode]="true" [wsType]="workspace.type"></mc-chart-list>
Parent TS
ngOnInit(): void {
this.charts = this.workspace.charts;
}
It look like this right now
You can use ChangeDetectorRef to detect changes on the view.
import {ChangeDetectorRef} from '#angular/core';
constructor(private ref: ChangeDetectorRef)
deleteChart(){
this.chartService.deleteChart(this.chart.guid).subscribe((deleted) => {
console.log(deleted);
this.ref.detectChanges();
});
}
Note: Remove changeDetection: ChangeDetectionStrategy.OnPush (if you are using it)
Related
I have the below partial HTML in my Material Table Angular application.
//HTML
<button mat-icon-button class="mat-18" (click)="updateStatus(element.id)"
[disabled]="validateToWork(element.reachedTime)">
<mat-icon>edit</mat-icon>
</button>
//Typescript
validateToWork(reachedTime:any):boolean{
if(reachedTime&& new Date(this.datePipe.transform(reachedTime, DATE_WITH_TIME)) < new Date())
return true;
else
return false;
}
The above code works fine and the edit button is disabled. But what i observed is when i have a console.log(reachedTime) in the typescript like,
console.log(reachedTime)
if(reachedTime&& new Date(this.datePipe.transform(reachedTime, DATE_WITH_TIME)) < new Date())
I could see the event is triggered on every mouseover i do on the table. Its weird for me and not sure. How can i stop that?
Below is the console log i have
Any help ?
Why
One of the rule with angular, is that you should try to avoid using method inside the html.
doing so
<button mat-icon-button class="mat-18" (click)="updateStatus(element.id)"
[disabled]="validateToWork(element.reachedTime)">
<mat-icon>edit</mat-icon>
</button>
Will force [disabled] to be recalculated each time you make any interaction with the page, mouseover being one.
To test this out, just scroll or click somewhere, you should have the same result.
How to fix it
Add the logic inside a pipe
import { DatePipe } from '#angular/common'
import { Pipe, PipeTransform } from '#angular/core'
import { DATE_WITH_TIME } from 'from/some/where'
#Pipe({
name: 'validateToWork',
})
export class ValidateToWorkPipe implements PipeTransform {
constructor(private datePipe: DatePipe) {}
transform(reachedTime: any): boolean {
// <- do add a definition, try to never use any
if (reachedTime && new Date(this.datePipe.transform(reachedTime, DATE_WITH_TIME)) < new Date())
return true
else return false
}
}
And use it in your code like follow
<button mat-icon-button class="mat-18" (click)="updateStatus(element.id)"
[disabled]="element.reachedTime | validateToWork">
<mat-icon>edit</mat-icon>
</button>
Further more
Do not forget to declare it in your module under the declarations: [] or in the imports: [] if you did create a module for that specific pipe
If you declares it directly, you won't be able to use it somewhere else.
If this is an object, you will have to manually trigger the update
In my ionic project I have 3 pages: HomeScreen, SearchPage & ScannerPage.
I navigate to SearchPage & ScannerPage from my HomeScreen via a routerlink as in my examples below:
<ion-button routerLink="/manual-qr-search" color= "tertiary" expand="block">Check Out</ion-button>
<ion-button disabled={{this.myService.getTempCardDisabled()}} routerLink="/manual-temperature-scanner" color= "primary" expand="full" class="flex-child"><ion-icon name="keypad-outline"></ion-icon>MANUAL</ion-button>
and I navigate back to the HomeScreen from my SearchPage using the android back button as follows:
this.platform.backButton.subscribeWithPriority(99999, () => {
this.router.navigate(['home-screen']);
});
and I navigate back to the HomeScreen from my ScannerPage using the android back button as follows:
this.platform.backButton.subscribeWithPriority(99999, () => {
this.router.navigate(['home-screen']);
});
My problem is the HomeScreen's ngOnInit() hits when I navigate from SearchPage but it doesn't hit when I navigate from ScannerPage and I want to know why.
I do not call ngOnDestroy() at all on any page.
I can put in a check to see when I navigate from another page so that the code inside the HomeScreen's ngOnInit() doesn't hit when I don't want it to but I feel like that is bad programming.
you can do the following if you want to check for event on page navigation change.
import { ActivatedRoute } from '#angular/router';
public class yourClassName{
constructor( private route: ActivatedRoute){
this.route.queryParams.subscribe((params) => {
// Do things when page changes routes
})
}
}
I have noticed that I had 2 paths set to my HomeScreen in my app-routing.module.ts folder which caused it to act this way. I added another route to call on ionViewWillEnter() and forgot to comment out the previous route.
The manual solutions for Auto Reloading the HTML page of a specific component:
Either by navigating to the HTML page on click.
Or calling the ngOnInit() of that component on click.
I am doing it manually using a click event from the HTML code as follows:
HTML Code: app.component.html
<button (click) = reloadPage()>
TS Code: app.component.ts
reloadPage() {
// Solution 1:
this.router.navigate('localhost:4200/new');
// Solution 2:
this.ngOnInit();
}
But I need to achieve this automatically. I hope I am clear. The page should auto-reload after some specific interval and call the ngOnInit() on each interval.
Add correct call to setInterval anywhere in your call:
setInterval(() => reloadPage(), 150000); and inside the method reloadPage put the same logic you have for the button.
An example:
Just put the reloadPage function call inside the constructor:
export class SomeComponent {
constructor() {
setInterval(() => this.reloadPage(), 150000);
}
reloadPage() {
// anything your button doeas
}
}
also note, that correct call of setInterval would be:
setInterval(() => this.reloadPage(), 150000);
Note: My answer just fixes the code you presented. But it seems there is some bigger logical misunderstanding of "reloading page" in angular and using ngOnInit
I'm running some e2e tests on an Angular2 app. One test involves clicking a button to open a Bootstrap modal. Even though I simulate the click of the button in my e2e test, it seems I cannot access the modal.
I'm currently just trying to run a simple test to click the button, open the modal, and check the text in an h4 element within the modal.
app.po.ts:
import { browser, element, by } from 'protractor';
export class SolarUi4Page {
navigateTo() {
return browser.get('http://localhost:4200/');
}
getAddButton() {
return element(by.css('.icon-plus'));
}
//2nd and 3rd lines attempt to do the same thing. Neither work
getH4() {
//return element(by.css('main-page')).element(by.id('data')).getText();
//return element(by.css('add-validation')).element(by.tagName('h4')).getText();
return element(by.css('h4')).getText();
}
}
app.e2e-spec.ts:
import { SolarUi4Page } from './app.po';
describe('solar-ui4 main page', function() {
let page: SolarUi4Page;
beforeEach(() => {
page = new SolarUi4Page();
});
it('should add new value to array/table and display it', () => {
page.navigateTo();
let addButton = page.getAddButton();
addButton.click();
expect(page.getH4()).toEqual('Add Data Point');
});
});
app.component.html (contains three custom components):
<main-page></main-page>
<add-validation></add-validation>
<delete-validation></delete-validation>
I am able to access any element inside the main-page component via syntax like the first commented out line in getH4() method. It seems I cannot access anything from the add-validation element, which is my Bootstrap modal. I'm assuming it is because that HTML is not present on the page on load, but shouldn't addButton.click(); trigger the modal to open so it IS present?
You might need to wait for the popup to be visible via browser.wait():
var EC = protractor.ExpectedConditions;
var elm = element(by.css('h4'));
browser.wait(EC.visibilityOf(elm), 5000);
expect(elm.getText()).toEqual('Add Data Point');
Below is part of code in parent component, I already get the enable value from eventEmitter in its child component, which is enable=true.
<img src="{{currentImg}}" alt="Play Image not found" (click)="onMouseClick()">
<pause-button (isPauseBtnClicked)="enable = $event"></pause-button>
status is: {{enable}}
Then how can I assign a value for currentImg="someImg.png" after it listened the eventEmitter(enable=true)? Should I write a function? if so, how can I call that function in img tag without any mouse event?
I konw with mouse click event, things becomes easier, currentImg can be assign a value inside function.
onMouseClick() {
this.currentImg = this.clickedImg;
}
Look I don't know what you want to achieve. But writing this answer by thinking that you want to go with EventEmitter way without calling any mouseevent.
Note: Your expectation might be different. But It might help you out. If doesn't, kindly use it as a reference. I might have understood something completely different but purpose is not to guide you in wrong way
<img src="{{currentImg}}" alt="Play Image not found" (click)="onMouseClick()">
<pause-button (isPauseBtnClicked)="fire($event)"></pause-button><br>
status is: {{enable}}<br> // haven't played with status
{{currentImg}}
boot.ts
fire(arg) {
console.log('test start');
//this.animate.subscribe((value) => { this.name = value; });
this.currentImg=arg;
console.log(arg);
}
Working Plunker
PasueButton.ts
#Component({
selector: 'pause-button ',
template: `
________________________________________________________
<br>
I'm child
<br>
<img src="img path" (click)="clickMe()"/>
<= click the img
<br>
_____________________________________________________
`
,
})
export class PasueButton implements OnInit {
#Output() isPauseBtnClicked: EventEmitter = new EventEmitter();
constructor() {
console.log('Constructor called');
}
ngOnInit() {
console.log('onit strat');
}
clickMe()
{
this.isPauseBtnClicked.next('child Img path is copied');
}
}