Como compartilhar observáveis ​​Knockout JS entre componentes da interface do usuário

12

Entendo como usar imports: {}eexports: {} compartilhar as propriedades dos componentes de uma interface do usuário, como:

defaults: {
    exports: {
        shouldShowMessage: '${$.component}'
    }
}

Que retorna o nome do componente nas exportações.

insira a descrição da imagem aqui

Mas quando tento exportar um observável do Knockout, ele é sempre indefinido:

defaults: {
    exports: {
        shouldShowMessage: '${$.shouldShowMessage}'
    }
}

...

setupKoBindings: function() {
    this.shouldShowMessage = ko.observable('Testing');
}

insira a descrição da imagem aqui

Como solução alternativa, vou criar um modelo de armazenamento conforme explicado aqui, mas eu preferiria usar as importações e exportações.

Ben Crook
fonte

Respostas:

12

Os valores do objeto de exportação precisam resolver para um nome e uma propriedade de uma instância UiComponent, separados por um ':', por exemplo checkout.cart.total:title.
O nome do destino de exportação deve incluir o componente de interface do usuário "namespace".

No seu exemplo, você define o valor como uma sequência, que é resolvida como uma propriedade do UiComponent que é a fonte de exportação. A exportação é indefinida quando você a inspeciona, porque esse não é um destino de exportação válido.

Aqui está um exemplo que funciona:

defaults: {
    exportTarget: "foo.bar",
    exportTargetProperty: "showMessage",

    tracks: {
        shouldShowMessage: true
    },

    exports: {
        shouldShowMessage: '${$.exportTarget}:${$.exportTargetProperty}'
    }
}
...

O texto acima copiará o valor da shouldShowMessagepropriedade para a propriedade showMessagede um UiComponent com o nome completo foo.bartoda vez que o valor for alterado.
Observe que isso não tornará automaticamente a propriedade de destino um KO também observável. Isso deve ser declarado explicitamente, se as alterações de valor acionarem o KO para renderizar novamente os nós DOM que acessam essa propriedade.

A propósito, adicionar shouldShowMessageao tracksobjeto o tornará um ko-es5 observável automagicamente. Usando um literal também ko.observable()funciona.

No exemplo acima, exportTargete exportTargetPropertysão configurados no defaults. Eles também podem ser especificados como parte das opções UiComponent no JSON, o que geralmente faz mais sentido, pois é aí que a hierarquia do UiComponent, incluindo os nomes do UiComponent, é definida.

Por fim, gostaria de observar que pessoalmente acho que sua solução usando um objeto de valor para passar o valor ao outro componente da interface do usuário é melhor do que usar exportações ou importações. Na minha experiência, manter o estado compartilhado no DOM ou nos UiComponents é uma receita para OOP de espaguete em todos os casos, exceto nos mais simples.

Vinai
fonte
Excelente explicação, obrigado @Vinai! Vou tentar quando tiver tempo e marcar isso como aceito, se funcionar.
Ben Crook
Eu me deparei com alguns problemas ao usar tracks, a assinatura manual de observáveis ​​não funciona mais this.shouldShowMessage.subscribe is not a functionao usá- this.shouldShowMessage.subscribe(function() { ... }); lo Funciona bem ao definir observáveis ​​de qualquer outra maneira. Parece que estou perdendo um passo ou tracksnão cria um observável da mesma maneira.
Ben Crook
Você está certo, as propriedades não são mais observáveis ​​ko comuns, apenas os pares ES5 getter / setter. Se você deseja acessar a função observável original, pode injetar ko e usar ko.getObservable(this, 'shouldShowMessage').subscribe(function(newValue) { ...});(o primeiro argumento é o viewmodel ( this), o segundo o nome da propriedade rastreada. Mais informações aqui: github.com/SteveSanderson/knockout-es5
Vinai
Ahh que faz sentido, você é o melhor <3
Ben Crook
1
Depois de brincar com importações e exportações e ainda falhar, eu concordo que esse é um código espaguete, eu desisti e continuarei com assinaturas manuais e um modelo de armazenamento.
Ben Crook