web-dev-qa-db-fra.com

AfterRender fonctionne-t-il avec les composants Knockout?

afterRender fonctionne avec les liaisons de modèles, mais après avoir converti mes modèles en composants, il ne semble pas y avoir de moyen d'utiliser afterRender. J'ai essayé de chercher un exemple de composant qui utilise afterRender, mais je ne trouve rien.

25
Eric Kolotyluk

Je n'ai pas pu faire fonctionner la méthode selon le post ci-dessus. Cependant, j'ai trouvé une solution de contournement sur la liste des problèmes git et cela ne nécessite pas de liaison KO personnalisée.

Ajoutez la ligne ci-dessous dans votre modèle de composant html ou chaîne de code.

 <span data-bind="template: { afterRender: init }"></span>

Créez ensuite une fonction init dans votre module/viewModel:

 this.init = function() {
   Do cool DOM stuff here.
}

ou en fonction de votre structure viewModel:

viewModel: function(params) {
    return {
        init: function () {

        }
    };
},

Fonctionne comme un charme. Un exemple de fonctionnement est ici

http://jsfiddle.net/gLcfxkv6/1/

Enfilez sur git knockout ici: https://github.com/knockout/knockout/issues/15

Merci aux vamps sur git pour la solution de contournement.

36
Piotr Stulinski

Le secret ici est http://knockoutjs.com/documentation/custom-bindings.html

ko.bindingHandlers.myCustomBinding = {
  init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    // This will be called when the binding is first applied to an element
    // Set up any initial state, event handlers, etc. here
    if (bindingContext.$data.init) bindingContext.$data.init(element, valueAccessor, allBindings, viewModel, bindingContext);
  },
  update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    // This will be called once when the binding is first applied to an element,
    // and again whenever any observables/computeds that are accessed change
    // Update the DOM element based on the supplied values here.
    if (bindingContext.$data.update) bindingContext.$data.update(element, valueAccessor, allBindings, viewModel, bindingContext);
  }
};

donc dans mon modèle de composant, je fais quelque chose comme

<div class="row-fluid" data-bind="myCustomBinding: 'someValue'">

et sur le composant viewModel j'implémente juste init et/ou update, par exemple:

constructor.prototype.init = function(element, valueAccessor, allBindings, viewModel, bindingContext) {
  // All the buttons in the buttons group need the same name,
  // but they all need distinct ids. We use timestamps because
  // as components, the names and ids should be distinct across
  // multiple instances of each component.
  var timeStamp = new Date().getTime();
  $('input:radio').attr('name', timeStamp).button();
  $('input:radio:eq(0)').attr('id', timeStamp+1);
  $('input:radio:eq(1)').attr('id', timeStamp+2);
  $('input:radio:eq(2)').attr('id', timeStamp+3);

  // Initialize the number-picker
  $('input[name="number-picker"]').TouchSpin();
};

La documentation de Knockout pourrait être améliorée en soulignant ce cas très utile. En outre, il s'agit d'une telle liaison utile, il devrait y avoir des liaisons standard pour "init" et "update", par exemple

<div data-bind="init: 'someValue'">
8
Eric Kolotyluk

Nous avions besoin d'accéder aux éléments DOM d'un composant après avoir basculé entre différents composants. Nous aurions aimé utiliser la liaison "afterRender" non existante sur les composants.

Nous l'avons résolu avec un setTimeout Javascript, laissant KO faire son rendu en premier, et en fait, la mise en file d'attente de notre code après cela.

HTML:

<div data-bind="component: compName"></div>

Le code de commutation du composant:

var compName = ko.observable();

//...

compName(switchToComponent);
setTimeout(function(){
    // this code is queued until after the component is rendered.
}, 0);
6
Arjan Einbu