Aleksandar Toplek
Aleksandar Toplek

Reputation: 2821

JavaScript inside KO Template

How to put script inside knockout template?

This doesn't work:

<script type="text/html" id="some-template">
    <div>
    ...
        <script type="text/javascript"> <!-- This is the problem -->
            CoinWidgetCom.go({
                wallet_address: "ENTER-YOUR-BITCOIN-WALLET-ADDRESS"
                , currency: "bitcoin"
                , counter: "count"
                , alignment: "bl"
                , qrcode: true
                , auto_show: false
                , lbl_button: "Donate"
                , lbl_address: "My Bitcoin Address:"
                , lbl_count: "donations"
                , lbl_amount: "BTC"
            });
        </script>
    ...
    </div>
</script>

...

<script src="http://coinwidget.com/widget/coin.js"></script>

This is the script that I'm trying to run inside each of the elements that use some-template. Script could maybe be modified, but I would rather use original version.

Upvotes: 4

Views: 3249

Answers (1)

Jeroen
Jeroen

Reputation: 63709

What you want is not possible. I don't think script tags with executable javascript inside a text/html script will have their code executed when the template is rendered.

However, like other commenters said: you don't need to do this. Rework your design, make use of Knockout's features for these type of things. There are several alternative solutions, including:

Creating your own bindingHandler to activate the widget on a rendered template. You have posted only a small portion of code, but here's what that would look like:

ko.bindingHandlers.myWidget = {
    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
        console.log('Initializing widget with ' + ko.toJSON(allBindings()['myWidget']));
    },
    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.
    }
};

var VmForTemplate = function() { }

var ViewModel = function() {
  this.subVm = new VmForTemplate();
};

ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<script type="text/html" id="some-template">
  <div data-bind='myWidget: {
                      wallet_address: "ENTER-YOUR-BITCOIN-WALLET-ADDRESS"
                      , currency: "bitcoin"
                      , counter: "count"
                      , alignment: "bl"
                      , qrcode: true
                      , auto_show: false
                      , lbl_button: "Donate"
                      , lbl_address: "My Bitcoin Address:"
                      , lbl_count: "donations"
                      , lbl_amount: "BTC"
                    }'>
  ... template ...
  </div>
</script>


<!-- ko template: { name: 'some-template', data: subVm } -->
<!-- /ko -->

Alternatively, use the afterRender attribute of the template binding, like so:

var VmForTemplate = function() { }

var ViewModel = function() {
  this.subVm = new VmForTemplate();
  this.initWidget = function() { CoinWidgetCom.go({
                wallet_address: "ENTER-YOUR-BITCOIN-WALLET-ADDRESS"
                , currency: "bitcoin"
                , counter: "count"
                , alignment: "bl"
                , qrcode: true
                , auto_show: false
                , lbl_button: "Donate"
                , lbl_address: "My Bitcoin Address:"
                , lbl_count: "donations"
                , lbl_amount: "BTC"
            }); };
};

ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<script type="text/html" id="some-template">
    <div>
       Template. No javascript here.
    </div>
</script>

<script>
  // Mock the widget
  var CoinWidgetCom = { go: function(opts) { console.log('Running widget with options: ' + ko.toJSON(opts)); } };
</script>

<!-- ko template: { name: 'some-template', data: subVm, afterRender: initWidget } -->
<!-- /ko -->

Upvotes: 4

Related Questions