Jr Tabuloc Jr Tabuloc - 8 days ago 6
Javascript Question

How to centralize knockout component registration?

Disclaimer : Apology for lenghty post as I want to briefly describe my problem.

I have created basic knockout component and it was totally working fine but I came to the point that everytime I want to use my component into other template I need to require it to it's consumer/viewmodel before it works (or else it will complain mycomponent is unknow) which makes me think that it violate DRY principle. Instead I want it to be part of knockout.

Scenario : mycomponent registration

/*mycomponent registration */

define(
[
"knockout",
"text!components/my-component-template.htm",
"components/my-component-view-model"
],
function (ko, myComponentTemplate, MyComponentViewModel)
{
"use strict";

ko.components.register("mycomponent",
{
viewModel:
{
createViewModel: function (params)
{
return new MyComponentViewModel(params);
}
},

template: myComponentTemplate
});
});


And I use it by requiring it as normal like :

Example 1 :

/* template of other consumer */

<ul data-bind='normal knockout function'>
<li>
<a href='#sample-only'></a>
<!-- ko component: { name: "mycomponent", params: { data : $data } } -->
<!-- /ko -->
</li>
</ul>

/* other view model 1*/

define(
[
"knockout",
"mycomponent" --> I want to eliminate this and make it part of knockout
],
function ()
{
"use strict";
/* Normal coding stuff here */
});


Example 2 : lets pretend this is different for sample purposes

/* other template that want to use mycomponent */
<ul data-bind='other template'>
<li>
<a href='#sample-only'></a>
<!-- ko component: { name: "mycomponent", params: { data : $data } } -->
<!-- /ko -->
</li>
</ul>

/* other view model 2 */

define(
[
"knockout",
"mycomponent" --> I want to eliminate this and make it part of knockout
],
function ()
{
"use strict";
/* Normal coding stuff here */
});


I tried to experiment by understanding how the custom loader works and realized none of the examples in the link that instantiate their view model manually via
createViewModel
like my example above. Then, another approach that I thought is much simplier is to create
knockout-extension.js
use it to register my components and other knockout file like custome binding handler etc. and require it in my index.cshtml like below:

/* knockout-extension.js */
define(
[
"<path>/mycomponent" --> Found in Scenario mycomponent registration above
],
function()
{
/* do nothing*/
})


/* Index */

<script type="text/javascript">

require({
baseUrl: '@Url.Content("~/Content/js")',
waitSeconds: 45,
paths:
{
/*
. other dependencies here
*/
"knockout" : "<path>/knockback-extensions"
}
});


But this approach lead to load time out problem like in this link which I can't resolve.

Can someone shed me little lights or is this even possible? How could I eliminate repetition of requiring my component every now and then to it's consumer but instead I want it to be part of my knockout. I want to centralize the registration in one single file whithout requiring it to its consumer. As of now it is quite of a pain.

Answer

I got a clue in this link wherein you can require inside define function. This resolve my issue on view model.

define(
[
    "knockout"
    "require"        
],
function (ko, require)
{
    "use strict";

    require(
    [
       "components/my-component-view-model"
    ],
    function (MyComponentViewModel)
    {
        ko.components.register("mycomponent",
        {
            viewModel:
            {
                createViewModel: function (params)
                {
                    return new MyComponentViewModel(params);
                }
            },

            template: { require : 'text!template-path-here' }
        });
    });
});
Comments