最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Multiple knockout components in the same view - Stack Overflow

programmeradmin4浏览0评论

I've searched high and low for an answer to this but can't for the life of me figure out what I'm doing differently from the official example, aside from the fact that I think my use case is a bit more plicated:

.html

Basically, I'm trying to create reusable UI elements. The behavior will essentially be passed to them via the "params" object. I want multiple elements to be able to exist on a single page, however, which is where I'm running into difficulty.

I'm using browserify to bundle my code and have the following (some entries truncated for brevity):

index.html

<div data-bind='ponent: { name: "toggle" , params: {
   enabledText: "Parental controls are enabled",
   disabledText: "Parental controls are disabled"
 }}'></div>
 <div data-bind='ponent: { name: "toggle" , params: {
   enabledText: "Same ponent, different behavior: enabled",
   disabledText: "Same ponent, different behavior: disabled"
 }}'></div>

main.js

var ko = window.ko = require('knockout'),
    toggle = require('./ponents/toggle/toggle');

koponents.register('toggle', toggle);

function Container() {

}

var con = new Container();

ko.applyBindings(con);

ponents/toggle/toggle.js

var ko = require('knockout'),
    template = require('./toggle.html');

function vm(params) {
  var self = this;
  self.enabled = ko.observable(false);
  self.label = koputed(function() {
    return self.enabled() ? params.enabledText : params.disabledText;
  });
}

module.exports = { viewModel: vm, template: template };

And finally, in ponents/toggle/toggle.html:

<input type='checkbox' data-bind='checked: enabled' id='switch-checkbox' class='switch-input' />
<label for='switch-checkbox' class='switch-input-label'>
  <span data-bind='text: label'></span>
</label>

The issue I'm having is that the ponents both appear on the page appropriately, but clicking the second one activates the first one (and does nothing for the seconD). I'm new to Knockout and am clearly missing something, but I can't figure out how to fix my issue. Any help would be immensely appreciated!

The strange thing is that the labels are appropriately unique, indicating that the ponents (view models) being instantiated for each HTML entity are, in fact, unique...however, it seems knockout's "checked" binding is only binding to the first.

EDIT: I know it's customary to include an example, so here's one on codepen. I apologize for using browserified code but hopefully it's still readable:

I've searched high and low for an answer to this but can't for the life of me figure out what I'm doing differently from the official example, aside from the fact that I think my use case is a bit more plicated:

http://knockoutjs./documentation/ponent-binding.html

Basically, I'm trying to create reusable UI elements. The behavior will essentially be passed to them via the "params" object. I want multiple elements to be able to exist on a single page, however, which is where I'm running into difficulty.

I'm using browserify to bundle my code and have the following (some entries truncated for brevity):

index.html

<div data-bind='ponent: { name: "toggle" , params: {
   enabledText: "Parental controls are enabled",
   disabledText: "Parental controls are disabled"
 }}'></div>
 <div data-bind='ponent: { name: "toggle" , params: {
   enabledText: "Same ponent, different behavior: enabled",
   disabledText: "Same ponent, different behavior: disabled"
 }}'></div>

main.js

var ko = window.ko = require('knockout'),
    toggle = require('./ponents/toggle/toggle');

ko.ponents.register('toggle', toggle);

function Container() {

}

var con = new Container();

ko.applyBindings(con);

ponents/toggle/toggle.js

var ko = require('knockout'),
    template = require('./toggle.html');

function vm(params) {
  var self = this;
  self.enabled = ko.observable(false);
  self.label = ko.puted(function() {
    return self.enabled() ? params.enabledText : params.disabledText;
  });
}

module.exports = { viewModel: vm, template: template };

And finally, in ponents/toggle/toggle.html:

<input type='checkbox' data-bind='checked: enabled' id='switch-checkbox' class='switch-input' />
<label for='switch-checkbox' class='switch-input-label'>
  <span data-bind='text: label'></span>
</label>

The issue I'm having is that the ponents both appear on the page appropriately, but clicking the second one activates the first one (and does nothing for the seconD). I'm new to Knockout and am clearly missing something, but I can't figure out how to fix my issue. Any help would be immensely appreciated!

The strange thing is that the labels are appropriately unique, indicating that the ponents (view models) being instantiated for each HTML entity are, in fact, unique...however, it seems knockout's "checked" binding is only binding to the first.

EDIT: I know it's customary to include an example, so here's one on codepen. I apologize for using browserified code but hopefully it's still readable:

http://codepen.io/sunny-mittal/pen/OVBNwp

Share Improve this question edited Jul 24, 2015 at 7:10 Moppo 19.3k5 gold badges67 silver badges65 bronze badges asked Jul 24, 2015 at 6:08 sunny-mittalsunny-mittal 5097 silver badges14 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 8

When you load multiple instances of this ponent the id attribute on the input tag and the for attribute on the label tag, that make up your ponent, are no longer going to be unique to the page.

You essentially have two input tags with the same id and two label tags targeting one id. Your label for="switch-checkbox" on the second ponent is picking up input id="switch-ponent" from the first ponent and not the second.

Though knockout ponents are great, unfortunately there is no dom isolation between instances of ponents.

To resolve this issue you need to ensure the values for id and for in each instance of your ponent are unique to the entire page.

I have included a snippet below of this working.

var uid = function(){
  var seed = 1;
  return { 
    new: function(p){
      return p + (seed++);
    }
  }
}();


    var template =
      "<input type='checkbox' data-bind='checked: enabled, attr: {id:id}' class='switch-input' />\n<label data-bind='attr: {for: id}' class='switch-input-label'>\n  <span data-bind='text: label'></span>\n</label>\n";

    var viewModel = function vm(params) {
      var self = this;
      self.id = uid.new('switch-checkbox-');
      self.enabled = ko.observable(false);
      self.label = ko.puted(function() {
        return self.enabled() ? params.enabledText : params.disabledText;
      });
    }

    var ponent = {
      viewModel: viewModel,
      template: template
    };

    ko.ponents.register('toggle', ponent);

    var vm = {};

    ko.applyBindings(vm);
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
html {
  position: relative;
  height: 100%;
  min-height: 100%;
}
.switch-input {
  display: none;
}
.switch-input-label {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
  position: relative;
  display: inline-block;
  cursor: pointer;
  font-weight: 500;
  text-align: left;
  margin: 16px;
  padding: 16px 0 16px 44px;
}
.switch-input-label:before,
.switch-input-label:after {
  content: '';
  position: absolute;
  margin: 0;
  outline: 0;
  top: 50%;
  transform: translate(0, -50%);
  transition: all 0.3s ease;
}
.switch-input-label:before {
  left: 1px;
  width: 34px;
  height: 14px;
  background-color: #9e9e9e;
  border-radius: 8px;
}
.switch-input-label:after {
  left: 0;
  width: 20px;
  height: 20px;
  background-color: #fafafa;
  border-radius: 50%;
  box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.14), 0 2px 2px 0 rgba(0, 0, 0, 0.098), 0 1px 5px 0 rgba(0, 0, 0, 0.084);
}
.switch-input:checked + .switch-input-label:before {
  background-color: #a5d6a7;
}
.switch-input:checked + .switch-input-label:after {
  background-color: #4caf50;
  transform: translate(80%, -50%);
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/knockout/3.2.0/knockout-min.js"></script>


<div data-bind='ponent: { name: "toggle" , params: {
   enabledText: "Parental controls are enabled",
   disabledText: "Parental controls are disabled"
 }}'></div>

<div data-bind='ponent: { name: "toggle" , params: {
   enabledText: "Same ponent, different behavior: enabled",
   disabledText: "Same ponent, different behavior: disabled"
 }}'></div>

<div data-bind='ponent: { name: "toggle" , params: {
   enabledText: "Same ponent, another instance: enabled",
   disabledText: "Same ponent, another instance: disabled"
 }}'></div>

发布评论

评论列表(0)

  1. 暂无评论