Écoute des changements de variables dans JavaScript

462

Est-il possible d'avoir un événement dans JS qui se déclenche lorsque la valeur d'une certaine variable change? JQuery est accepté.

rashcroft22
la source
@BenjaminGruenbaum vous voulez probablement dire MutableObserver (pour DOM). L'objet est uniquement pour les objets JS de ce que je me souviens.
HellBaby
2
@HellBaby cette question concerne les variables - pas le DOM.
Benjamin Gruenbaum du
9
@BenjaminGruenbaum selon developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Object.observe est obsolète ou obsolète. Le remplacement recommandé (par cette même page) est l'objet Proxy.
stannius
4
La question ne pose que des questions variable, mais toutes les réponses se réfèrent ici property. Je me demande si nous pouvons écouter les local variablechangements.
Thariq Nugrohotomo
1
y a-t-il une réponse à cela? Je veux dire, pour en sélectionner un
Braian Mellor

Réponses:

100

Oui, c'est désormais tout à fait possible!

Je sais que c'est un vieux fil mais maintenant cet effet est possible en utilisant des accesseurs (getters et setters): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters

Vous pouvez définir un objet comme celui-ci, dans lequel aInternalreprésente le champ a:

x = {
  aInternal: 10,
  aListener: function(val) {},
  set a(val) {
    this.aInternal = val;
    this.aListener(val);
  },
  get a() {
    return this.aInternal;
  },
  registerListener: function(listener) {
    this.aListener = listener;
  }
}

Vous pouvez ensuite enregistrer un auditeur en utilisant les éléments suivants:

x.registerListener(function(val) {
  alert("Someone changed the value of x.a to " + val);
});

Ainsi, chaque fois que quelque chose change la valeur de x.a, la fonction d'écoute sera déclenchée. L'exécution de la ligne suivante fera apparaître la fenêtre d'alerte:

x.a = 42;

Voir un exemple ici: https://jsfiddle.net/5o1wf1bn/1/

Vous pouvez également utiliser un tableau d'écouteurs au lieu d'un seul emplacement d'écoute, mais je voulais vous donner l'exemple le plus simple possible.

Akira
la source
6
Il s'agit d'une tonne de code par objet, existe-t-il un moyen de le rendre plus réutilisable?
Vael Victus
Où est ton code? En avez-vous commencé une nouvelle question?
Akira
Qu'en est-il d'un moyen de détecter quand une nouvelle propriété a été ajoutée à un objet, ou si une a été supprimée?
Michael
C'est une vieille réponse, mais je voulais ajouter que cela fonctionne bien pour les valeurs de tableau aussi longtemps que vous définissez la valeur du tableau au lieu de pousser dessus.
TabsNotSpaces
1
Vous devez simplement avoir un tableau d'écouteurs au lieu d'un seul, puis au lieu d'appeler simplement this.aListener(val), vous devrez parcourir toutes les fonctions d'écoute et appeler chacune en passant val. En règle générale, la méthode est appelée à la addListenerplace de registerListener.
Akira
75

La plupart des réponses à cette question sont obsolètes, inefficaces ou nécessitent l'inclusion de grandes bibliothèques gonflées:

  • Object.watch et Object.observe sont tous deux obsolètes et ne doivent pas être utilisés.
  • onPropertyChange est un gestionnaire d'événements d'élément DOM qui ne fonctionne que dans certaines versions d'IE.
  • Object.defineProperty vous permet de rendre une propriété d'objet immuable, ce qui vous permettrait de détecter les tentatives de modification, mais cela bloquerait également toute modification.
  • La définition des setters et des getters fonctionne, mais elle nécessite beaucoup de code de configuration et ne fonctionne pas bien lorsque vous devez supprimer ou créer de nouvelles propriétés.

Aujourd'hui, vous pouvez désormais utiliser l' objet Proxy pour surveiller (et intercepter) les modifications apportées à un objet. Il est spécialement conçu pour ce que le PO essaie de faire. Voici un exemple de base:

var targetObj = {};
var targetProxy = new Proxy(targetObj, {
  set: function (target, key, value) {
      console.log(`${key} set to ${value}`);
      target[key] = value;
      return true;
  }
});

targetProxy.hello_world = "test"; // console: 'hello_world set to test'

Les seuls inconvénients de l' Proxyobjet sont:

  1. L' Proxyobjet n'est pas disponible dans les anciens navigateurs (comme IE11) et le polyfill ne peut pas répliquer entièrement la Proxyfonctionnalité.
  2. Les objets proxy ne se comportent pas toujours comme prévu avec des objets spéciaux (par exemple, Date) - l' Proxyobjet est mieux couplé avec des objets ou des tableaux simples.

Si vous devez observer les modifications apportées à un objet imbriqué , vous devez utiliser une bibliothèque spécialisée telle que Observable Slim (que j'ai publiée) qui fonctionne comme ceci:

var test = {testing:{}};
var p = ObservableSlim.create(test, true, function(changes) {
    console.log(JSON.stringify(changes));
});

p.testing.blah = 42; // console:  [{"type":"add","target":{"blah":42},"property":"blah","newValue":42,"currentPath":"testing.blah",jsonPointer:"/testing/blah","proxy":{"blah":42}}]
Elliot B.
la source
1
J'ajouterai également un autre inconvénient, vous ne regardez pas réellement les modifications sur l'objet cible mais uniquement sur l'objet proxy. Dans certains cas, vous voulez simplement savoir quand une propriété change sur l'objet cible (par exemple target.hello_world = "test")
Cristiano
2
you don't actually watch changes on the target object but only on proxy object- ce n'est pas tout à fait exact. L' Proxyobjet n'est pas modifié - il n'a pas sa propre copie de la cible. you just want to know when a property change on the target object- vous pouvez accomplir cela avec un Proxy, c'est l'un des principaux cas d'utilisation des proxys.
Elliot
2
Non, car vous modifiez directement la cible. Si vous souhaitez observer la modification target, vous devez le faire via un proxy. Cependant, proxy.hello_world = "test"cela ne signifie pas que vous modifiez le proxy, le proxy reste inchangé, targetest modifié (si votre gestionnaire d'ensemble est configuré pour le faire). On dirait que votre point est que vous ne pouvez pas observer directement target.hello_world = "test". C'est vrai. Les affectations de variables simples n'émettent aucun type d'événement. C'est pourquoi nous devons utiliser des outils comme ceux décrits dans les réponses à cette question.
Elliot
2
Merci Elliot B. It sounds like your point is that you cannot directly observe target.hello_world = "test". That is true.c'est exactement ce que je veux dire. Dans mon cas, j'ai un objet créé ailleurs et mis à jour par un autre code ... un proxy, dans ce cas, n'est pas utile car les modifications seront effectuées sur la cible.
Cristiano
1
@Cristiano Je suppose qu'Elliot essaie de dire que vous pouvez utiliser le proxy au lieu de l'objet réel, ce qui signifie que vous pouvez passer le proxy comme s'il s'agissait de votre objet et faire interagir les autres parties de l'application avec votre proxy. Les modifications apportées au proxy seront répercutées sur l'objet réel.
Zoltán Matók
33

Non.

Mais, si c'est vraiment si important, vous avez 2 options (la première est testée, la seconde ne l'est pas):

Tout d'abord, utilisez des setters et des getters, comme ceci:

var myobj = {a : 1};

function create_gets_sets(obj) { // make this a framework/global function
    var proxy = {}
    for ( var i in obj ) {
        if (obj.hasOwnProperty(i)) {
            var k = i;
            proxy["set_"+i] = function (val) { this[k] = val; };
            proxy["get_"+i] = function ()    { return this[k]; };
        }
    }
    for (var i in proxy) {
        if (proxy.hasOwnProperty(i)) {
            obj[i] = proxy[i];
        }
    }
}

create_gets_sets(myobj);

alors vous pouvez faire quelque chose comme:

function listen_to(obj, prop, handler) {
    var current_setter = obj["set_" + prop];
    var old_val = obj["get_" + prop]();
    obj["set_" + prop] = function(val) { current_setter.apply(obj, [old_val, val]); handler(val));
}

puis définissez l'auditeur comme:

listen_to(myobj, "a", function(oldval, newval) {
    alert("old : " + oldval + " new : " + newval);
}

Deuxièmement, j'ai en fait oublié, je vais soumettre pendant que j'y pense :)

EDIT: Oh, je me souviens :) Vous pouvez mettre une montre sur la valeur:

Étant donné myobj ci-dessus, avec 'a' dessus:

function watch(obj, prop, handler) { // make this a framework/global function
    var currval = obj[prop];
    function callback() {
        if (obj[prop] != currval) {
            var temp = currval;
            currval = obj[prop];
            handler(temp, currval);
        }
    }
    return callback;
}

var myhandler = function (oldval, newval) {
    //do something
};

var intervalH = setInterval(watch(myobj, "a", myhandler), 100);

myobj.set_a(2);
Luke Schafer
la source
8
"regarder" ne détecte pas réellement un changement. Ce n'est pas basé sur un événement et ralentirait certainement très rapidement l'ensemble de l'application. Ces approches à mon humble avis ne devraient jamais faire partie d'un vrai projet.
Muhammad bin Yusrat
28

En utilisant Prototype: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

// Console
function print(t) {
  var c = document.getElementById('console');
  c.innerHTML = c.innerHTML + '<br />' + t;
}

// Demo
var myVar = 123;

Object.defineProperty(this, 'varWatch', {
  get: function () { return myVar; },
  set: function (v) {
    myVar = v;
    print('Value changed! New value: ' + v);
  }
});

print(varWatch);
varWatch = 456;
print(varWatch);
<pre id="console">
</pre>

Autre exemple

// Console
function print(t) {
  var c = document.getElementById('console');
  c.innerHTML = c.innerHTML + '<br />' + t;
}

// Demo
var varw = (function (context) {
  return function (varName, varValue) {
    var value = varValue;
  
    Object.defineProperty(context, varName, {
      get: function () { return value; },
      set: function (v) {
        value = v;
        print('Value changed! New value: ' + value);
      }
    });
  };
})(window);

varw('varWatch'); // Declare
print(varWatch);
varWatch = 456;
print(varWatch);

print('---');

varw('otherVarWatch', 123); // Declare with initial value
print(otherVarWatch);
otherVarWatch = 789;
print(otherVarWatch);
<pre id="console">
</pre>

Eduardo Cuomo
la source
Le deuxième exemple est un peu trompeur, varwnécessite 2 arguments mais une partie de votre exemple montre que la fonction est appelée avec juste le paramètre value.
Hlawuleka MAS
22

Désolé de faire apparaître un vieux fil, mais voici un petit manuel pour ceux qui (comme moi!) Ne voient pas comment l'exemple d'Eli Grey fonctionne:

var test = new Object();
test.watch("elem", function(prop,oldval,newval){
    //Your code
    return newval;
});

J'espère que cela peut aider quelqu'un

javascript est futur
la source
9
La montre n'est pas prise en charge sur Chrome ou Safari pour le moment, seulement Firefox
Paul McClean
5
Par réseau de développeurs mozilla, ce n'est pas recommandé. Object.prototype.watch () était destiné aux tests uniquement et ne doit pas être utilisé dans le code de production. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Dennis Bartlett
4
@PaulMcClean cette réponse était en réponse à la réponse d'Eli Grey qui contenait un Polyfill. gist.github.com/eligrey/384583
Hobbyist
2
la montre est déconseillée par Mozilla. Cette réponse pourrait être trompeuse.
Arnaud
7

Comme la réponse de Luke Schafer ( note : cela fait référence à son message d'origine; mais le point ici reste valable après la modification ), je suggère également une paire de méthodes Get / Set pour accéder à votre valeur.

Cependant, je suggérerais quelques modifications (et c'est pourquoi je poste ...).

Un problème avec ce code est que le champ ade l'objet myobjest directement accessible, il est donc possible d'y accéder / changer sa valeur sans déclencher les écouteurs:

var myobj = { a : 5, get_a : function() { return this.a;}, set_a : function(val) { this.a = val; }}
/* add listeners ... */
myobj.a = 10; // no listeners called!

Encapsulation

Donc, pour garantir que les auditeurs sont effectivement appelés, il faudrait interdire cet accès direct au terrain a. Comment faire Utilisez une fermeture !

var myobj = (function() { // Anonymous function to create scope.

    var a = 5;            // 'a' is local to this function
                          // and cannot be directly accessed from outside
                          // this anonymous function's scope

    return {
        get_a : function() { return a; },   // These functions are closures:
        set_a : function(val) { a = val; }  // they keep reference to
                                            // something ('a') that was on scope
                                            // where they were defined
    };
})();

Vous pouvez maintenant utiliser la même méthode pour créer et ajouter les écouteurs comme l'a proposé Luke, mais vous pouvez être assuré qu'il n'y a aucun moyen possible de lire ou d'écrire a passer inaperçu!

Ajout de champs encapsulés par programme

Toujours sur la piste de Luke, je propose maintenant un moyen simple d'ajouter des champs encapsulés et les getters / setters respectifs aux objets au moyen d'un simple appel de fonction.

Notez que cela ne fonctionnera correctement qu'avec les types de valeur . Pour que cela fonctionne avec les types de référence , une sorte de copie complète devrait être implémentée (voir celle-ci , par exemple).

function addProperty(obj, name, initial) {
    var field = initial;
    obj["get_" + name] = function() { return field; }
    obj["set_" + name] = function(val) { field = val; }
}

Cela fonctionne de la même manière qu'auparavant: nous créons une variable locale sur une fonction, puis nous créons une fermeture.

Comment l'utiliser? Facile:

var myobj = {};
addProperty(myobj, "total", 0);
window.alert(myobj.get_total() == 0);
myobj.set_total(10);
window.alert(myobj.get_total() == 10);
Bruno Reis
la source
2
+1 pour l'encapsulation. C'était ma première pensée, mais je voulais éventuellement pouvoir ajouter la méthode create_gets_sets, et comme c'est aveugle, cacher les valeurs n'est pas cool :) nous pouvons aller plus loin et écrire quelques choses pour cacher les valeurs, mais Je pense que le code que j'ai publié est assez déroutant pour la plupart des gens ... peut-être s'il y a un appel à cela ...
Luke Schafer
6

Si vous utilisez jQuery {UI} (que tout le monde devrait utiliser :-)), vous pouvez utiliser .change () avec un élément <input /> caché.

Chuck Han
la source
7
Je ne comprends pas très bien. Comment pouvez-vous attacher une variable à un <input/>élément caché ?
Peter Lee
4
Je pense que Chuck suggère que vous pouvez définir la valeur de l'entrée à l'aide de jquery, puis d'un écouteur d'événements .change (). Si vous mettez à jour la valeur de l'entrée avec .val (), le rappel d'événement .change () se déclenchera.
jarederaj
2
<input type="hidden" value="" id="thisOne" />et avec jQuery $("#thisOne").change(function() { do stuff here });et $("#thisOne").val(myVariableWhichIsNew);puis le .change()feu se déclenche.
khaverim
2
C'est la meilleure solution dans mes livres. Simple, facile. Au lieu de changer la variable dans votre code, par exemple var1 = 'new value';, vous allez plutôt définir la valeur de cette entrée cachée, puis ajouter un écouteur pour changer la variable. $("#val1").on('change', function(){ val1 = this.val(); ... do the stuff that you wanted to do when val1 changed... }); $("#val1").val('new value');
Tom Walker
2
Pour tous ceux qui ont le même problème que moi, si l'événement de changement ne se déclenche pas, essayez $ ("# thisOne"). Val (myVariableWhichIsNew) .trigger ('change'). J'espère que cela aide
Alator
6

AngularJS(Je sais que ce n'est pas le cas JQuery, mais cela pourrait aider. [Pure JS est bon en théorie uniquement]):

$scope.$watch('data', function(newValue) { ..

où "data" est le nom de votre variable dans la portée.

Il y a un lien vers doc.

ses
la source
Malheureusement, cela vous oblige à lier une variable à la portée
ruX
il n'est tiré que lorsqu'il $scope.$apply()est exécuté
iamawebgeek
5

Pour ceux qui accordent quelques années plus tard:

Une solution pour la plupart des navigateurs (et IE6 +) est disponible qui utilise l'événement onpropertychange et la nouvelle spécification defineProperty. Le léger hic, c'est que vous devrez faire de votre variable un objet dom.

Tous les détails:

http://johndyer.name/native-browser-get-set-properties-in-javascript/

MandoMando
la source
3

La fonctionnalité que vous recherchez peut être obtenue grâce à l'utilisation de la méthode "defineProperty ()" - qui n'est disponible que pour les navigateurs modernes:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

J'ai écrit une extension jQuery qui a des fonctionnalités similaires si vous avez besoin de plus de support multi-navigateurs:

https://github.com/jarederaj/jQueue

Une petite extension jQuery qui gère la mise en file d'attente des rappels à l'existence d'une variable, d'un objet ou d'une clé. Vous pouvez affecter un nombre quelconque de rappels à un nombre quelconque de points de données susceptibles d'être affectés par des processus s'exécutant en arrière-plan. jQueue écoute et attend que ces données que vous spécifiez apparaissent, puis déclenche le rappel correct avec ses arguments.

jarederaj
la source
2

Pas directement: vous avez besoin d'une paire getter / setter avec une interface "addListener / removeListener" de quelque sorte ... ou un plugin NPAPI (mais c'est une autre histoire).

jldupont
la source
1
//ex:
/*
var x1 = {currentStatus:undefined};
your need is x1.currentStatus value is change trigger event ?
below the code is use try it.
*/
function statusChange(){
    console.log("x1.currentStatus_value_is_changed"+x1.eventCurrentStatus);
};

var x1 = {
    eventCurrentStatus:undefined,
    get currentStatus(){
        return this.eventCurrentStatus;
    },
    set currentStatus(val){
        this.eventCurrentStatus=val;
      //your function();
    }
};

ou

/*  var x1 = {
eventCurrentStatus:undefined,
currentStatus : {
    get : function(){
        return Events.eventCurrentStatus
        },
    set : function(status){
        Events.eventCurrentStatus=status;

    },
}*/
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
x1.currentStatus="create"
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
x1.currentStatus="edit"
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
console.log("currentStatus = "+ x1.currentStatus);

ou

/* global variable ku*/
    var jsVarEvents={};
    Object.defineProperty(window, "globalvar1", {//no i18n
        get: function() { return window.jsVarEvents.globalvarTemp},
        set: function(value) { window.window.jsVarEvents.globalvarTemp = value; }
    });
    console.log(globalvar1);
    globalvar1=1;
    console.log(globalvar1);
Avatar
la source
1

Une solution assez simple et simpliste consiste à simplement utiliser un appel de fonction pour définir la valeur de la variable globale et ne jamais définir sa valeur directement. De cette façon, vous avez un contrôle total:

var globalVar;

function setGlobalVar(value) {
    globalVar = value;
    console.log("Value of globalVar set to: " + globalVar);
    //Whatever else
}

Il n'y a aucun moyen d'imposer cela, cela nécessite simplement une discipline de programmation ... bien que vous puissiez utiliser grep(ou quelque chose de similaire) pour vérifier que votre code ne définit directement la valeur deglobalVar .

Ou vous pouvez l'encapsuler dans un objet et des méthodes getter et setter utilisateur ... juste une pensée.

markvgti
la source
Pour une variable qui n'est pas une propriété d'un objet, on peut accéder - comme c'est le cas avec les variables déclarées avec vardans les modules ES6 - c'est la seule solution.
amn
1

Veuillez vous rappeler que la question initiale était pour les VARIABLES, pas pour les OBJETS;)

en plus de toutes les réponses ci-dessus, j'ai créé une minuscule bibliothèque appelée forTheWatch.js , qui utilise la même manière pour intercepter et rappeler les modifications des variables globales normales en javascript.

Compatible avec les variables JQUERY, pas besoin d'utiliser des OBJETS, et vous pouvez passer directement un TABLEAU de plusieurs variables si nécessaire.

Si cela peut être utile ...: https://bitbucket.org/esabora/forthewatch
Fondamentalement, il vous suffit d'appeler la fonction:
watchIt("theVariableToWatch", "varChangedFunctionCallback");

Et désolé par avance si non pertinent.

Soufiane Benrazzouk
la source
1

La façon la plus simple que j'ai trouvée, à partir de cette réponse :

// variable holding your data
const state = {
  count: null,
  update() {
    console.log(`this gets called and your value is ${this.pageNumber}`);
  },
  get pageNumber() {
    return this.count;
  },
  set pageNumber(pageNumber) {
    this.count = pageNumber;
    // here you call the code you need
    this.update(this.count);
  }
};

Et alors:

state.pageNumber = 0;
// watch the console

state.pageNumber = 15;
// watch the console
Giorgio Tempesta
la source
1

Dans mon cas, j'essayais de savoir si une bibliothèque que j'incluais dans mon projet redéfinissait la mienne window.player. Donc, au début de mon code, je viens de faire:

Object.defineProperty(window, 'player', {
  get: () => this._player,
  set: v => {
    console.log('window.player has been redefined!');
    this._player = v;
  }
});
José Antonio Postigo
la source
0

Ce n'est pas directement possible.

Cependant, cela peut être fait en utilisant CustomEvent: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent

La méthode ci-dessous accepte un tableau de noms de variables en entrée et ajoute un écouteur d'événements pour chaque variable et déclenche l'événement pour toute modification de la valeur des variables.

La méthode utilise l'interrogation pour détecter la modification de la valeur. Vous pouvez augmenter la valeur du délai d'expiration en millisecondes.

function watchVariable(varsToWatch) {
    let timeout = 1000;
    let localCopyForVars = {};
    let pollForChange = function () {
        for (let varToWatch of varsToWatch) {
            if (localCopyForVars[varToWatch] !== window[varToWatch]) {
                let event = new CustomEvent('onVar_' + varToWatch + 'Change', {
                    detail: {
                        name: varToWatch,
                        oldValue: localCopyForVars[varToWatch],
                        newValue: window[varToWatch]
                    }
                });
                document.dispatchEvent(event);
                localCopyForVars[varToWatch] = window[varToWatch];
            }
        }
        setTimeout(pollForChange, timeout);
    };
    let respondToNewValue = function (varData) {
        console.log("The value of the variable " + varData.name + " has been Changed from " + varData.oldValue + " to " + varData.newValue + "!!!"); 
    }
    for (let varToWatch of varsToWatch) {
        localCopyForVars[varToWatch] = window[varToWatch];
        document.addEventListener('onVar_' + varToWatch + 'Change', function (e) {
            respondToNewValue(e.detail);
        });
    }
    setTimeout(pollForChange, timeout);
}

En appelant la méthode:

watchVariables(['username', 'userid']);

Il détectera les modifications apportées aux variables nom d'utilisateur et ID utilisateur.

Ketan Yekale
la source
0

Avec l'aide de getter et setter , vous pouvez définir une classe JavaScript qui fait une telle chose.

Tout d'abord, nous définissons notre classe appelée MonitoredVariable:

class MonitoredVariable {
  constructor(initialValue) {
    this._innerValue = initialValue;
    this.beforeSet = (newValue, oldValue) => {};
    this.beforeChange = (newValue, oldValue) => {};
    this.afterChange = (newValue, oldValue) => {};
    this.afterSet = (newValue, oldValue) => {};
  }

  set val(newValue) {
    const oldValue = this._innerValue;
    // newValue, oldValue may be the same
    this.beforeSet(newValue, oldValue);
    if (oldValue !== newValue) {
      this.beforeChange(newValue, oldValue);
      this._innerValue = newValue;
      this.afterChange(newValue, oldValue);
    }
    // newValue, oldValue may be the same
    this.afterSet(newValue, oldValue);
  }

  get val() {
    return this._innerValue;
  }
}

Supposons que nous voulons écouter les moneychangements, créons une instance de MonitoredVariableavec de l'argent initial 0:

const money = new MonitoredVariable(0);

Ensuite, nous pourrions obtenir ou définir sa valeur en utilisant money.val:

console.log(money.val); // Get its value
money.val = 2; // Set its value

Puisque nous n'avons défini aucun écouteur pour cela, rien de spécial ne se produit après money.val modifications apportées à 2.

Définissons maintenant certains écouteurs. Nous avons quatre auditeurs disponibles: beforeSet, beforeChange, afterChange, afterSet. Les événements suivants se produisent séquentiellement lorsque vous utilisez money.val = newValuepour modifier la valeur de la variable:

  1. money.beforeSet (newValue, oldValue);
  2. money.beforeChange (newValue, oldValue); (Sera ignoré si sa valeur n'est pas modifiée)
  3. money.val = newValue;
  4. money.afterChange (newValue, oldValue); (Sera ignoré si sa valeur n'est pas modifiée)
  5. money.afterSet (newValue, oldValue);

Maintenant, nous définissons l' afterChangeécouteur qui ne sera déclenché qu'après avoir money.valchangé (alors que afterSetsera déclenché même si la nouvelle valeur est la même que l'ancienne):

money.afterChange = (newValue, oldValue) => {
  console.log(`Money has been changed from ${oldValue} to ${newValue}`);
};

Maintenant, définissez une nouvelle valeur 3et voyez ce qui se passe:

money.val = 3;

Vous verrez ce qui suit dans la console:

Money has been changed from 2 to 3

Pour le code complet, voir https://gist.github.com/yusanshi/65745acd23c8587236c50e54f25731ab .

yusanshi
la source
-2

C'est un vieux fil de discussion mais je suis tombé sur la deuxième réponse la plus élevée (écouteurs personnalisés) tout en recherchant une solution utilisant Angular. Alors que la solution fonctionne, angular a une meilleure manière intégrée de résoudre ce problème en utilisant des @Outputémetteurs d'événements. En sortant de l'exemple dans l'écouteur personnalisé, répondez:

ChildComponent.html

<button (click)="increment(1)">Increment</button>

ChildComponent.ts

import {EventEmitter, Output } from '@angular/core';

@Output() myEmitter: EventEmitter<number> = new EventEmitter<number>();

private myValue: number = 0;

public increment(n: number){
  this.myValue += n;

  // Send a change event to the emitter
  this.myEmitter.emit(this.myValue);
}

ParentComponent.html

<child-component (myEmitter)="monitorChanges($event)"></child-component>
<br/>
<label>{{n}}</label>

ParentComponent.ts

public n: number = 0;

public monitorChanges(n: number){
  this.n = n;
  console.log(n);
}

Cela sera désormais mis à jour nsur le parent à chaque fois que le bouton enfant est cliqué. Stackblitz de travail

TabsNotSpaces
la source
-3
Utils = {
    eventRegister_globalVariable : function(variableName,handlers){
        eventRegister_JsonVariable(this,variableName,handlers);
    },
    eventRegister_jsonVariable : function(jsonObj,variableName,handlers){
        if(jsonObj.eventRegisteredVariable === undefined) {
            jsonObj.eventRegisteredVariable={};//this Object is used for trigger event in javascript variable value changes ku
        }
        Object.defineProperty(jsonObj, variableName , {
                    get: function() { 
                        return jsonObj.eventRegisteredVariable[variableName] },
                    set: function(value) {
                        jsonObj.eventRegisteredVariable[variableName] = value; handlers(jsonObj.eventRegisteredVariable[variableName]);}
                    });
            }
Avatar
la source