Hi All,
When I change an HTMLElement
in the DOM, the change is not reflected.
I have an html img
element:
<img class="selected" id="icon-image-{{item.id}}" src="{{item.icon}}" height="75" width="75" />
and some sccs :
img.selected {
-webkit-filter: grayscale(100%); /* Chrome, Safari, Opera */
filter: grayscale(100%);
}
When this loads, it applies the selected
class, and makes the image grey as expected.
However, when I run the following typescrpt the image just stays grey:
let imgEl: HTMLElement = document.getElementById('icon-image-' + subCategoryModel.id);
imgEl.className = "";
When I log the className
, it shows selected
is there before, and has been removed after.
console.log(imgEl.classList);
Any ideas why, even though I remove a className
, the style is not reflected?
When I look at the source code, it is not updating the DOM, but imgEl.classList
is being changed. Do you know why?
Thanks
Something strange, if I change the className in the DOM manually (in Firebug for example), it reflects the change. However, as soon as I click the image, it updates to what the original value was. It is as if the DOM is being refreshed.
If this is the case, then how is it possible to update the DOM dynamically? Because the DOM refresh just overwrites all changes.
Html
<ion-row *ngFor="let trio of getTriples()">
<ion-col *ngFor="let item of trio" (click)="itemTapped(item)">
<center>
<div class="row responsive-md">
<img class="selected" id="icon-image-{{item.id}}" src="{{item.icon}}" height="75" width="75" />
</div>
</center>
</ion-col>
</ion-row>
Typescript
itemTapped(subCategoryModel: SubCategoryModel) {
let idx: number = this.isInArray(this.employeeModel.subCategories, subCategoryModel);
let imgEl: HTMLElement = document.getElementById('icon-image-' + subCategoryModel.id);
if (idx >= 0) {
this.employeeModel.subCategories.splice(idx, 1);
imgEl.setAttribute("class", "");
} else {
this.employeeModel.subCategories.push(subCategoryModel);
imgEl.setAttribute("class", "selected");
}
console.log('icon-image-'+subCategoryModel.id+' ('+imgEl.id+'): ' + document.getElementById('icon-image-' + subCategoryModel.id).className);
}
Is this a scope issue, am I updating the wrong document? Whatâs the answer, Iâm confused. Appreciate any help. I do a simplified version in jsfiddle and it works, so I think this maybe has something to do with Ionic2?
I did try this with no success:
changeDetection: ChangeDetectionStrategy.OnPush
Also tried:
setTimeout( () => {
imgEl.setAttribute("class", "");
},500);
And also tried returning the function as a Promise
.
How do I do the following in Ionic 2?
$scope.$apply()
Here is something that says in Angular you canât manipulate the DOM. What are you supposed to do then if you want to make style changes dynamically?
It says that one should change the scope. How do you do that? Does that mean you need duplicate objects? If so, is that not bad practice?
What is the best solution?
This discussion suggests, to use NgZone
? It also talks about additional plugins.
I try the following with no success:
this.zone.run(() => {
imgEl.setAttribute("class", "");
});
I have also tried ChangeDetectorRef detectChanges()
.
Any advise appreciated.
Probably same problem here.
I have an ion-list items and user can add some data.
If I add data with my addNoteKeyboard() function, all will be ok, data will be shown properly and my list update.
Using addNoteMic() function, that is, use speech to text, nothing would be displayed until the first iteration with the screen (but i see the data immediately in console log).
.start() of course , allows to start recording and onresult = function(event) allows to receive the data.
Thatâs my code:
myList.html
<ion-item (click)âŚ
Hi Moscardini, it may be similar. However, I did try NgZone
with no success. Not sure if it will work for you, but look at my previous comment.
From what I have been reading it looks like Angular doesnât allow DOM manipulation. Seems like a serious limitation, and I canât seem to find a solution as yet.
Here is a similar issue too.
This is a really weird problem that I cannot seem to solve! I am trying to change the text in an element (given the id and fetched by querySelector) and change itâs text from âhelloâ to âgoodbyeâ. The code only seems to work once, then never again after that. Iâve tried refreshing and the text would just stay as âhelloâ. The only way I could solve this was by copy and pasting the example code back into it and then refreshing (Which is the really really weird part). Iâm fairly sure it isnât cacheâŚ
Let give it a try.
If works, tell me something
Iâm trying it too now.
Hi Moscardini, looks like he suggests to use NgZone
.
this.ngZone.run(() => {...});
Iâve tried that with no success, but hope it works for you.
jjmax
August 4, 2016, 7:48am
9
Hi,
tl;dr - I think [class.active] is what youâre after
If youâre just looking to add a class on a condition then I use something like the following in Ionic 2 -
item.html
<ion-item class="item-stable" (click)="toggleItem(item)" [class.active]="itemShown === item"> {{item.name}} </ion-item>
item.ts
...
this.itemShown = null;
isItemShown(item) {
return this.itemShown === item;
}
toggleItem(item) {
if (this.isItemShown(item)) {
this.itemShown = null;
} else {
this.itemShown = item;
}
}
...
To breakdown whatâs happening here -
A list of items is created on the DOM, initially no item is âactiveâ (itemShown is null)
If an item is clicked the toggleItem() function is called with the item object as a parameter
The toggleItem() function checks if the item is currently active, if not it sets itemShown to the item, if currently active it sets itemShown to null
The [class.item]=âitemShown === itemâ sets the active class on the DOM element if the itemShown variable is set to that DOM elements item
Iâm not sure if this is what youâre looking for or if my explanation has made it any clearer. Let me know if you need more info.
1 Like
ngZone work like a charm for me!
Maybe you are doing something not right, thatâs my code.
You can check old code in my topic.
import { Component, NgZone } from '@angular/core';
import { NavController, Alert, reorderArray} from 'ionic-angular';
declare var SpeechRecognition: any;
@Component({
templateUrl: 'build/pages/notes/notes.html',
})
export class NotesPage {
_zone: any;
recognition: any;
listaSpesa: any = [];
constructor(private nav: NavController, _zone: NgZone) {
this._zone = _zone;
this.recognition = new SpeechRecognition();
this.recognition.lang = 'it-IT';
this.recognition.onresult = (event => {
if (event.results.length > 0) {
console.log('--> risultati: ', event.results[0][0].transcript);
this._zone.run(() => this.listaSpesa.push({alimento: event.results[0][0].transcript}));
}
console.log('--> SpeechRecognition: listening END');
});
}
addNoteMic() {
console.log('--> SpeechRecognition: listening');
this.recognition.start();
}
1 Like
Hi Moscardini,
Iâm glad it works for you.
I have tried it,
this._zone.run(() => { imgEl.setAttribute("class", ""); });
with no success unfortunately. Unless you van see what I am doing incorrectly?
jjmax has suggested a toggle function above which I am going to try too.
2 Likes
Hi jjmax,
I understand that you are showing a toggle switch, but I donât understand how you get it to update the className
on the HTMLElement
(img
) to the item-selected
class?
I have the following code:
scss
img.item-selected {
-webkit-filter: grayscale(100%); /* Chrome, Safari, Opera */
filter: grayscale(100%);
}
img.item-stable {
}
html
<ion-row *ngFor="let trio of getTriples()">
<ion-col *ngFor="let item of trio">
<center>
<div class="row responsive-md">
<img class="item-stable" (click)="toggleItem(item)" [class.active]="itemShown === item" id="icon-image-{{item.id}}" src="{{item.icon}}" height="75" width="75" />
</div>
</center>
</ion-col>
</ion-row>
ts
isItemShown(item) {
return this.itemShown === item;
}
toggleItem(item) {
if (this.isItemShown(item)) {
this.itemShown = null;
} else {
this.itemShown = item;
}
console.log('toggleItem: '+item+': '+this.itemShown);
}
jjmax
August 4, 2016, 9:03am
13
quick fix I think
Just change [class.active] to [class.item-selected]
The bit after [class. is the class that will be added to your element
1 Like
jjmax
August 4, 2016, 9:05am
14
Also, have you created a variable in the ts file?
It would be something like this:
itemShown: any;
.....
(in constructor)
this.itemShown = itemShown;
Thank you jjmax, that works!! I was missing the[class.item-selected]
.
Thank you for your help, I was really struggling.
jjmax
August 4, 2016, 9:14am
16
No problem, it had me a few days ago too