webpackknockout.jswebpack-html-loader

Run external function when knockout component is created


I am trying to create new component in knockout:

ko.components.register("categories", {
    viewModel: {
        instance: MY_VIEW_MODEL
    },
    template: require('html-loader?interpolate!./components/categories.html')
});

and my HTML block inside of categories.html:

<div class="panel" data-bind="foreach: categories, afterRender: ${require('../effects.js').fadePanels()}"></div>

and inside of effect.js:

function fadePanels() {
    $('.panel').velocity('fadeInPanels', {
        stagger: 250,
    })
}

plus webpack.config.js:

    test: /\.html$/,
    loader: 'html-loader',
    options: {
        interpolate: true
    },
    exclude: /node_modules/

but it's not working at all. Here is the output from browser (no errors in console): enter image description here

Do you have any experience with this? Do you know how to correctly handle that?


Solution

  • You can run a function that takes a component's element by using the createViewmodel factory method. This function receives an info object that includes the current element.

    ko.components.register("category", {
        viewModel: { 
          createViewModel: (params, info) => {
            fadeIn(info.element);
            return { label: "hello world" }
          } 
        },
        template: `<div data-bind="text: label"></div>`
    });
    
    const categories = ko.observableArray(["", "", ""]);
    const addCat = () => categories.push("");
    
    ko.applyBindings({ categories, addCat  });
    
    function fadeIn(el) {
      el.classList.add("seeThrough");
      setTimeout(
        () => el.classList.add("fadeIn"), 
        200
      );
    }
    .seeThrough {
      opacity: 0;
      transition: opacity .25s ease-in-out;
    }
    
    .fadeIn {
      opacity: 1;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    <ul data-bind="foreach: categories">
      <li data-bind="component: { name: 'category' }"></li>
    </ul>
    
    <button data-bind="click: addCat">add</button>

    For working with components and webpack, you might want to check out this answer I wrote a few days ago. It describes how to configure webpack to work with knockout components.