Ouvindo alterações variáveis ​​no JavaScript

462

É possível ter um evento em JS que é acionado quando o valor de uma determinada variável é alterado? JQuery é aceito.

rashcroft22
fonte
@BenjaminGruenbaum provavelmente você quer dizer MutableObserver (para DOM). O objeto é apenas para objetos JS, pelo que me lembro.
HellBaby
2
@ HellBaby esta pergunta é sobre variáveis ​​- não o DOM.
Benjamin Gruenbaum 03/04
9
@BenjaminGruenbaum de acordo com developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Object.observe está obsoleto ou está obsoleto. A substituição recomendada (pela mesma página) é o objeto Proxy.
31516 stannius
4
A pergunta é apenas sobre variable, mas todas as respostas aqui se referem property. Eu me pergunto se podemos ouvir local variablemudanças.
Thariq Nugrohotomo 29/07
1
existe alguma resposta para isso? Quer dizer, para selecionar um
Braian Mellor

Respostas:

100

Sim, isso agora é completamente possível!

Sei que esse é um thread antigo, mas agora esse efeito é possível usando acessadores (getters e setters): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters

Você pode definir um objeto como este, no qual aInternalrepresenta o campo 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;
  }
}

Em seguida, você pode registrar um ouvinte usando o seguinte:

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

Portanto, sempre que algo mudar o valor de x.a, a função de ouvinte será acionada. A execução da seguinte linha exibirá o pop-up de alerta:

x.a = 42;

Veja um exemplo aqui: https://jsfiddle.net/5o1wf1bn/1/

Você também pode usar uma matriz de ouvintes em vez de um único slot de ouvinte, mas eu queria dar o exemplo mais simples possível.

Akira
fonte
6
É uma tonelada de código por objeto. Existe uma maneira de tornar isso mais reutilizável?
Vael Victus
Onde está o seu código? Você iniciou uma nova pergunta a partir dela?
Akira
Que tal uma maneira de detectar quando uma nova propriedade foi adicionada a um objeto ou uma foi removida?
Michael
Esta é uma resposta antiga, mas eu gostaria de acrescentar que isso funciona bem para valores de matriz, desde que você defina o valor da matriz em vez de pressioná-la.
TabsNotSpaces
1
Você simplesmente precisa ter um conjunto de ouvintes em vez de um único e, em vez de apenas chamar this.aListener(val), você terá que percorrer todas as funções do ouvinte e chamar cada uma delas de passagem val. Normalmente, o método é chamado em addListenervez de registerListener.
Akira
75

A maioria das respostas a esta pergunta está desatualizada, ineficaz ou requer a inclusão de grandes bibliotecas inchadas:

  • Object.watch e Object.observe estão obsoletos e não devem ser usados.
  • onPropertyChange é um manipulador de eventos do elemento DOM que funciona apenas em algumas versões do IE.
  • Object.defineProperty permite tornar imutável uma propriedade de objeto, o que permitiria detectar tentativas de alterações, mas também bloquearia quaisquer alterações.
  • Definir setters e getters funciona, mas exige muito código de instalação e não funciona bem quando você precisa excluir ou criar novas propriedades.

Hoje, agora você pode usar o objeto Proxy para monitorar (e interceptar) as alterações feitas em um objeto. Foi desenvolvido especificamente para o que o OP está tentando fazer. Aqui está um exemplo básico:

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'

Os únicos inconvenientes do Proxyobjeto são:

  1. O Proxyobjeto não está disponível em navegadores mais antigos (como o IE11) e o polyfill não pode replicar totalmente a Proxyfuncionalidade.
  2. Os objetos proxy nem sempre se comportam conforme o esperado com objetos especiais (por exemplo, Date) - o Proxyobjeto é melhor emparelhado com objetos ou matrizes simples.

Se você precisar observar as alterações feitas em um objeto aninhado , precisará usar uma biblioteca especializada, como o Observable Slim (que publiquei), que funciona assim:

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.
fonte
1
Acrescentarei também outra desvantagem: na verdade, você não observa alterações no objeto de destino, mas apenas no objeto de proxy. Em alguns casos, você só quer saber quando uma propriedade é alterada no objeto de destino (por exemplo,target.hello_world = "test" )
Cristiano
2
you don't actually watch changes on the target object but only on proxy object- isso não é bem preciso. O Proxyobjeto não é modificado - ele não possui sua própria cópia do destino. you just want to know when a property change on the target object- você pode fazer isso com a Proxy, esse é um dos principais casos de uso de proxies.
Elliot B.
2
Não, porque você está modificando o destino diretamente. Se você quiser observar a modificação target, precisará fazê-lo através de um proxy. No entanto, proxy.hello_world = "test"isso não significa que você está modificando o proxy, o proxy permanece inalterado, targeté modificado (se o manipulador de conjunto estiver configurado para isso). Parece que o seu ponto é que você não pode observar diretamente target.hello_world = "test". Isso é verdade. Designações de variáveis ​​simples não emitem nenhum tipo de evento. É por isso que temos que usar ferramentas como as descritas nas respostas a esta pergunta.
Elliot B.
2
Obrigado Elliot B. It sounds like your point is that you cannot directly observe target.hello_world = "test". That is true.Esse é exatamente o meu ponto. No meu caso, eu tenho um objeto criado em outro lugar e fui atualizado por outro código ... um proxy, nesse caso, não é útil, pois as alterações serão feitas no destino.
Cristiano
1
@ Cristiano Acho que o que Elliot está tentando dizer é que você pode usar o proxy em vez do objeto real, o que significa que você pode passar o proxy como se fosse seu objeto e fazer com que as outras partes do aplicativo interajam com o seu proxy. Alterações no proxy serão refletidas no objeto real.
Zoltán Matók
33

Não.

Mas, se é realmente tão importante, você tem 2 opções (a primeira é testada, a segunda não):

Primeiro, use setters e getters, assim:

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);

então você pode fazer algo como:

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));
}

defina o ouvinte como:

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

Em segundo lugar, eu realmente esqueci, vou enviar enquanto penso sobre isso :)

EDIT: Ah, eu me lembro :) Você pode colocar um relógio no valor:

Dado myobj acima, com 'a':

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
fonte
8
"assistir" não está realmente detectando uma alteração. Isso não é baseado em eventos e certamente desaceleraria o aplicativo inteiro muito em breve. Essas abordagens IMHO nunca devem fazer parte de um projeto real.
Muhammad bin Yusrat
28

Usando 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>

Outro exemplo

// 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
fonte
O segundo exemplo é um pouco enganador, varwrequer 2 argumentos, mas parte do seu exemplo mostra a função sendo chamada apenas com o parâmetro value.
Hlawuleka MAS
22

Desculpe trazer um tópico antigo, mas aqui está um pequeno manual para quem (como eu!) Não vê como o exemplo de Eli Grey funciona:

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

Espero que isso possa ajudar alguém

javascript é futuro
fonte
9
Relógio não é suportado no Chrome ou Safari, no momento, única Firefox
Paul McClean
5
Por rede de desenvolvedores do mozilla, isso não é recomendado. Object.prototype.watch () foi projetado apenas para teste e não deve ser usado no código de produção. developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Dennis Bartlett
4
@PaulMcClean, esta resposta foi em resposta à resposta de Eli Grey, que continha um Polyfill. gist.github.com/eligrey/384583
Hobbyist
2
O relógio foi descontinuado pelo Mozilla. Esta resposta pode ser enganosa.
Arnaud #
7

Como resposta de Luke Schafer ( nota : isso se refere ao seu post original; mas todo o ponto aqui permanece válido após a edição ), eu também sugeriria um par de métodos Get / Set para acessar seu valor.

No entanto, eu sugeriria algumas modificações (e é por isso que estou postando ...).

Um problema com esse código é que o campo ado objeto myobjé diretamente acessível, portanto, é possível acessá-lo / alterar seu valor sem acionar os ouvintes:

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!

Encapsulamento

Portanto, para garantir que os ouvintes sejam realmente chamados, teríamos de proibir esse acesso direto ao campo a. Como fazer isso? Use um fechamento !

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
    };
})();

Agora você pode usar o mesmo método para criar e adicionar os ouvintes que Luke propôs, mas tenha certeza de que não há como ler ou escrever para apassar despercebido!

Adicionando campos encapsulados programaticamente

Ainda na trilha de Luke, proponho agora uma maneira simples de adicionar campos encapsulados e os respectivos getters / setters aos objetos por meio de uma simples chamada de função.

Observe que isso só funcionará corretamente com tipos de valor . Para que isso funcione com tipos de referência , algum tipo de cópia profunda teria que ser implementado (veja este , por exemplo).

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

Isso funciona da mesma maneira que antes: criamos uma variável local em uma função e, em seguida, criamos um fechamento.

Como usá-lo? Simples:

var myobj = {};
addProperty(myobj, "total", 0);
window.alert(myobj.get_total() == 0);
myobj.set_total(10);
window.alert(myobj.get_total() == 10);
Bruno Reis
fonte
2
+1 para encapsulamento. Esse foi meu primeiro pensamento, mas eu queria adicionar o método create_gets_sets eventualmente e, como é indiscriminado, ocultar os valores não é legal :) podemos dar um passo adiante e escrever algumas coisas para ocultar os valores, mas Eu acho que o código que eu postada é confuso o suficiente para a maioria das pessoas ... talvez se há chamada para ele ...
Luke Schafer
6

Se você estiver usando jQuery {UI} (que todo mundo deveria usar :-)), poderá usar .change () com um elemento <input /> oculto.

Chuck Han
fonte
7
Eu não entendo direito. Como você pode anexar uma variável a um <input/>elemento oculto ?
Peter Lee
4
Acho que Chuck está sugerindo que você possa definir o valor da entrada usando jquery e, em seguida, um ouvinte de evento .change (). Se você atualizar o valor da entrada com .val (), o retorno de chamada do evento .change () será acionado.
jarederaj
2
<input type="hidden" value="" id="thisOne" />e com jQuery $("#thisOne").change(function() { do stuff here });e, em $("#thisOne").val(myVariableWhichIsNew);seguida, o .change()irá disparar.
Khaverim
2
Esta é a melhor solução nos meus livros. Simples, fácil. Em vez de alterar a variável no seu código, por exemplo var1 = 'new value';, você definirá o valor dessa entrada oculta e adicionará um ouvinte para alterar a variável. $("#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
Para quem está tendo o mesmo problema que eu, se a mudança evento doesnt gatilho tentar $ ( "# thisone") val (myVariableWhichIsNew) .trigger ( 'mudança') .Hope isso ajuda.
Alator
6

AngularJS(Eu sei que isso não é JQuery, mas isso pode ajudar. [JS puro é bom apenas em teoria]):

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

onde "dados" é o nome da sua variável no escopo.

Há um link para doc.

ses
fonte
Infelizmente o obriga a variável de ligação ao espaço
Rux
ele só é acionado quando $scope.$apply()é executado
iamawebgeek
5

Para aqueles que sintonizam alguns anos depois:

Está disponível uma solução para a maioria dos navegadores (e IE6 +) que usa o evento onpropertychange e a especificação mais recente defineProperty. O problema é que você precisará tornar sua variável um objeto dom.

Detalhes completos:

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

MandoMando
fonte
3

A funcionalidade que você procura pode ser alcançada através do uso do método "defineProperty ()" - disponível apenas para navegadores modernos:

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

Eu escrevi uma extensão jQuery que possui algumas funcionalidades semelhantes se você precisar de mais suporte entre navegadores:

https://github.com/jarederaj/jQueue

Uma pequena extensão jQuery que lida com retornos de chamada da fila para a existência de uma variável, objeto ou chave. Você pode atribuir qualquer número de retornos de chamada a qualquer número de pontos de dados que possam ser afetados por processos em execução em segundo plano. O jQueue escuta e aguarda que esses dados especificados existam e, em seguida, dispara o retorno de chamada correto com seus argumentos.

jarederaj
fonte
2

Não diretamente: você precisa de um getter / setter de pares com uma interface "addListener / removeListener" de algum tipo ... ou um plug-in NPAPI (mas isso é outra história).

jldupont
fonte
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
fonte
1

Uma solução bastante simples e simplista é usar apenas uma chamada de função para definir o valor da variável global e nunca definir seu valor diretamente. Dessa forma, você tem controle total:

var globalVar;

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

Não há como impor isso, apenas requer disciplina de programação ... embora você possa usar grep(ou algo semelhante) para verificar se em nenhum lugar o seu código define diretamente o valor deglobalVar .

Ou você pode encapsulá-lo em um objeto e métodos getter e setter do usuário ... apenas um pensamento.

markvgti
fonte
Para uma variável que não é propriedade de um objeto, pode-se acessar - como é o caso de variáveis ​​declaradas varnos módulos ES6 - essa é a única solução.
amn
1

Por favor, lembre-se de que a pergunta inicial era para VARIÁVEIS, não para OBJETOS;)

além de todas as respostas acima, criei uma pequena biblioteca chamada forWatch.js , que usa da mesma maneira para capturar e chamadas para alterações nas variáveis ​​globais normais em javascript.

Compatível com variáveis ​​JQUERY, não é necessário usar OBJETOS, e você pode transmitir diretamente um ARRAY de várias variáveis, se necessário.

Se puder ser útil ...: https://bitbucket.org/esabora/forthewatch
Basicamente, basta chamar a função:
watchIt("theVariableToWatch", "varChangedFunctionCallback");

E desculpe antecipadamente, se não for relevante.

Soufiane Benrazzouk
fonte
1

A maneira mais fácil que encontrei, partindo desta resposta :

// 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);
  }
};

E depois:

state.pageNumber = 0;
// watch the console

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

No meu caso, eu estava tentando descobrir se alguma biblioteca que eu estava incluindo no meu projeto estava redefinindo o meu window.player. Então, no início do meu código, eu apenas fiz:

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

Não é diretamente possível.

No entanto, isso pode ser feito usando o CustomEvent: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent

O método abaixo aceita uma matriz de nomes de variáveis ​​como uma entrada e adiciona um ouvinte de evento para cada variável e aciona o evento para qualquer alteração no valor das variáveis.

O método usa pesquisa para detectar a alteração no valor. Você pode aumentar o valor do tempo limite em milissegundos.

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);
}

Chamando o método:

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

Ele detectará as alterações nas variáveis ​​username e userid.

Ketan Yekale
fonte
0

Com a ajuda de getter e setter , você pode definir uma classe JavaScript que faz isso.

Primeiro, definimos nossa classe chamada 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;
  }
}

Suponha que desejamos ouvir as moneyalterações, vamos criar uma instância do MonitoredVariablecom dinheiro inicial 0:

const money = new MonitoredVariable(0);

Então poderíamos obter ou definir seu valor usando money.val:

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

Como não definimos nenhum ouvinte para isso, nada de especial acontece após as money.valalterações em 2.

Agora vamos definir alguns ouvintes. Temos quatro ouvintes disponíveis: beforeSet, beforeChange, afterChange, afterSet. O seguinte ocorrerá sequencialmente quando você usar money.val = newValuepara alterar o valor da variável:

  1. money.beforeSet (newValue, oldValue);
  2. money.beforeChange (newValue, oldValue); (Será ignorado se seu valor não for alterado)
  3. money.val = newValue;
  4. money.afterChange (newValue, oldValue); (Será ignorado se seu valor não for alterado)
  5. money.afterSet (newValue, oldValue);

Agora, definimos o afterChangeouvinte que será acionado somente após a money.valalteração (while afterSetserá acionado mesmo que o novo valor seja o mesmo que o antigo):

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

Agora defina um novo valor 3e veja o que acontece:

money.val = 3;

Você verá o seguinte no console:

Money has been changed from 2 to 3

Para obter o código completo, consulte https://gist.github.com/yusanshi/65745acd23c8587236c50e54f25731ab .

yusanshi
fonte
-2

Este é um tópico antigo, mas me deparei com a segunda resposta mais alta (ouvintes personalizados) enquanto procurava uma solução usando o Angular. Enquanto a solução funciona, o angular tem uma maneira melhor construída de resolver esse problema usando @Outputemissores e eventos. Saindo do exemplo na resposta do ouvinte personalizado:

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);
}

Agora, isso será atualizado nno pai cada vez que o botão filho for clicado. Stackblitz de trabalho

TabsNotSpaces
fonte
-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
fonte