Does afterRender work with Knockout components?

后端 未结 4 1564
小鲜肉
小鲜肉 2020-12-05 02:40

afterRender works with template bindings, but after converting my templates to components, there does not seem to be any way to use afterRender. I

相关标签:
4条回答
  • 2020-12-05 03:14

    I could not get the method working as per the above post. However i found a workaround on the git issue list and it doesn't require a custom KO Binding.

    Add the below line in your component template html or string of code.

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

    Then create a init function in your module / viewModel:

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

    or depending on your viewModel structure:

    viewModel: function(params) {
        return {
            init: function () {
    
            }
        };
    },
    

    Works like a charm. Example of it working is here

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

    Thread on knockout git here: https://github.com/knockout/knockout/issues/1533

    Thanks to vamps on git for the workaround.

    0 讨论(0)
  • 2020-12-05 03:27

    We needed to access DOM elements in a component after switching between different components. We would have liked to use the non-existing "afterRender" binding on components.

    We solved it with a Javascript setTimeout, letting KO do its rendering first, and in effect queueing our code after that.

    HTML:

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

    The code switching the component:

    var compName = ko.observable();
    
    //...
    
    compName(switchToComponent);
    setTimeout(function(){
        // this code is queued until after the component is rendered.
    }, 0);
    
    0 讨论(0)
  • 2020-12-05 03:32

    The secret here is 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);
      }
    };
    

    so in my component template I do something like

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

    and on the component viewModel I just implement init and/or update, for example:

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

    The Knockout documentation could be improved by pointing out this very useful case. Also, this is such a useful binding, there should be a standard bindings for 'init' and 'update', for example

    <div data-bind="init: 'someValue'">
    
    0 讨论(0)
  • 2020-12-05 03:34

    Make a new binding, like so

    ko.bindingHandlers.initBinding = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        debugger
        if (valueAccessor() && valueAccessor().afterRender && bindingContext.$data) {
            valueAccessor().afterRender(bindingContext.$data);
        }
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        }
    };
    
    export default ko.bindingHandlers.initBinding
    

    You don't need the export if you're not using ES6(babel etc).

    Then in your component html, you can do something like this

    <div class="staff-directory" data-bind="initBinding: {afterRender: afterRender }">
        <p>Loaded</p>
    </div>
    

    And in your component model

    class staffDirectory {
    
        constructor() {
            console.log('staff directory loaded');
        }
    
        afterRender() {
            console.log('afterRender called');
        }
    
    }
    
    export default staffDirectory;
    
    0 讨论(0)
提交回复
热议问题