3
votes

getAttribute de l'élément avec l'état (.active)

Je ne parviens pas à vérifier l'état actif d'un attribut d'élément . J'ai essayé ci-dessous mais il a retourné false même si l'élément a l'attribut dans un état actif - ( .c-banner.active est présent)

ngAfterViewInit() {
    const bannerElm = document.getElementById("banner");
    const isActive = bannerElm && bannerElm.getAttribute("class")
      .indexOf("c-banner.active") !== -1;  // returned false
}


5 commentaires

Alors, quelle est la valeur de bannerElm.getAttribute ("class") ?


.getAttribute ("class") va renvoyer l'attribut class exactement comme la valeur que vous voyez dans le DOM, alors pourquoi recherchez-vous c-banner.active avec un point et pas d'espace comme un sélecteur css?


il a renvoyé "c-banner". et oui @BenSewards, vous avez raison, il a renvoyé la valeur exactement telle quelle. Cependant, l'attribut attaché est .c-banner.active donc ma question est de savoir comment vérifier si le style css d'état .active a été appliqué. Thnx.


Je vois beaucoup de réponses sur la façon d'accéder correctement à la classe / classList. La valeur de l'attribut class lorsqu'il est coché dans le hook de cycle de vie ngAfterViewInit est prétendument c-banner . L'élément n'est peut-être pas dans l'état attendu en raison d'une opération de nature asynchrone? Comment définissez-vous l'état actif de la bannière? pouvez-vous essayer d'obtenir la classe d'élément après un délai d'attente? (juste à des fins de débogage)


@JanWendland setTimeout en combinaison avec classList.contains a fonctionné pour moi !! Merci les gars!


4 Réponses :


1
votes

Vous pouvez utiliser la méthode classList.contains pour vérifier si l'élément a la classe active.

ngAfterViewInit() {
    setTimeout(() => {
        const isActive = bannerElm &&
                         bannerElm.classList.contains('c-banner') &&
                         bannerElm.classList.contains('active');
    }, 1000);
}

[UPDATED] l'enveloppez dans setTimeout () et cela a fonctionné ! Au cas où quelqu'un d'autre serait coincé avec le problème des commandes d'initialisation des composants que j'avais précédemment.


2 commentaires

@ user11151040 vous y a fait :)


@benshabatnoam oui, mais dans l'ensemble, il contient du travail :)



3
votes

Pourquoi n'utilisez-vous pas classList et contains?

classList . contains (); p>

 ngAfterViewInit() {
    const bannerElm = document.getElementById("banner");
    const isActive = bannerElm && bannerElm.classList.contains('c-banner') && bannerElm.classList.contains('active');
}


2 commentaires

@ user11151040 L'exemple de code que vous aviez était incorrect. Cela devrait être .classList.contains (). Même si vous étiez plus rapide, mais je choisis l'autre réponse. Juste pour info, vous pouvez toujours cliquer sur "modifier" et revalider la réponse.


@displayname oui vous avez raison. Après avoir mentionné l'explication, j'ai oublié comment l'ajouter au contenu, c'est très drôle :) Maintenant, je l'ai édité.



0
votes

vous devriez travailler avec ViewChild plutôt qu'accéder directement à votre DOM. les deux fonctionneront, mais c'est la manière stricte de le faire.

@ViewChild('banner') input; 
ngAfterViewInit() {
    var classAttributes= this.input.nativeElement.getAttribute('class');
    var result=classAttributes&&classAttributes('c-banner')
}


0 commentaires

1
votes

Mis à part la meilleure façon d'accéder à la valeur de l'attribut class, à en juger par vos commentaires, le problème semble être de nature asynchrone. Pour éviter d'utiliser une solution hackish setTimeout , je recommanderais d'appliquer un observateur de mutation et de réagir aux modifications de l'attribut en conséquence. Voici une façon de procéder.

PS: Modification de la réponse pour la rendre plus adaptée à ce que vous essayez d'accomplir. En fin de compte, cela ne fera pas une énorme différence à part cela dans le cas où l'état de la bannière est changé avant la fin du temps anti-rebond, le sujet émet tout de suite et vous gagnez potentiellement du temps d'attente par rapport à l'utilisation de setTimeout code>

bannerIsActive$ = new BehaviorSubject<boolean>(false);

ngAfterViewInit() {
    const banner = document.getElementById('banner');

    const observer = new MutationObserver((mutations: MutationRecord[]) => {
        const mutation = mutations[0];
        const classList: DOMTokenList = mutation.target['classList'];
        this.bannerIsActive$.next(mutation.attributeName === 'class' && classList.contains('active'));
    });

    observer.observe(banner, {
        attributes: true
    });

    this.bannerIsActive$.pipe(
         debounce(isActive => timer(isActive ? 0 : 1000)),
         take(1)
    ).subscribe(isActive => {
       // do something with the banner state
    });
}


5 commentaires

@janwedland gentil! QQ. Que faire si je ne veux obtenir l'état qu'une seule fois et ignorer le changement d'état? J'ai pensé à vous abonner et à vous inscrire, mais il y a peut-être une meilleure solution!


Je dirais que cela dépend de ce que vous essayez de faire avec l'État. Utilisez-vous l'état dans votre modèle de composant? Dans ce cas, vous pouvez simplement l'initialiser avec false sur votre composant et demander au rappel de l'écouteur de mutation de le mettre à jour au cas où la bannière serait activée.


Si le scénario est un peu plus complexe et que vous voulez faire une sorte de demande en fonction de l'état de la bannière, vous pouvez créer un BehaviourSubject sur votre composant, l'initialiser avec false, vous y abonner avec un temps anti-rebond de ce pour quoi vous semblez raisonnable l'opération asynchrone pour rattraper et appeler la méthode suivante du sujet de l'observateur de mutation. Vous pouvez ensuite vous y abonner et peu importe si l'état de la bannière change ou non, vous obtiendrez l'état actuel de la bannière après le temps anti-rebond. Mais peut-être pouvez-vous expliquer davantage ce que vous essayez d'accomplir? @Afficher un nom


@displayname A modifié cette approche dans ma réponse.


Je l'ai essayé mais il n'a pas capturé l'état actif.