最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - knockout.js get parent observable - Stack Overflow

matteradmin5PV0评论

Is it possible to get parent observable in knockout? Like I have

<div data-bind="parent: {...}">
   <div data-bind="child: {...}">
      ...
   </div>
</div>

I want to get access to parent in child but not in the markup but in the code. How can I achieve in a standard knockout way?

UPDATE I have found a simple way to achieve this by simply accessing the last argument of custom handler like this:

ko.bindingHandlers.custom = {
  init: function (element, valueAccessor, allBindingsAccessor, vm, bindingContext) {
     console.log(bindingContext.$parent);
  }
}

Is it possible to get parent observable in knockout? Like I have

<div data-bind="parent: {...}">
   <div data-bind="child: {...}">
      ...
   </div>
</div>

I want to get access to parent in child but not in the markup but in the code. How can I achieve in a standard knockout way?

UPDATE I have found a simple way to achieve this by simply accessing the last argument of custom handler like this:

ko.bindingHandlers.custom = {
  init: function (element, valueAccessor, allBindingsAccessor, vm, bindingContext) {
     console.log(bindingContext.$parent);
  }
}
Share Improve this question edited Mar 12, 2014 at 11:02 lukas.pukenis asked Mar 12, 2014 at 10:14 lukas.pukenislukas.pukenis 13.6k13 gold badges49 silver badges83 bronze badges 0
Add a ment  | 

2 Answers 2

Reset to default 3

You can use $parent to access the parent item:

<div data-bind="parent: {...}">
   <div data-bind="child: {...}">
      <span data-bind="text: $parent.someObservable()"></span>
      <span data-bind="text: somefunction($parent.someObservable())"></span>
   </div>
</div>

The most simple way it to past parent object to child model as a parameter (pointer) when child object constructed. But it more standard javascript way then knockout

var Parent = function (item) {
    var self = this;

    this.value = ko.observable(item.value);
    this.child = new Child(item.child, self);
}

var Child = function (item, parent) {
    var self = this;

    this.parent = parent;
    this.value = ko.observable(item.value);
}

and HTML markup will look like

This is <b><span data-bind="text: value"></span></b>

<div data-bind="with: child">
    This is <b><span data-bind="text: value"></span></b>
    <br/>
    This is <b><span data-bind="text: parent.value"></span></b> of <b><span data-bind="text: value"></span></b>
</div>

JSFIDDLE

To prevent big amount of code mapping plugin could be used and it will be more knockout way

var Parent = function (item) {
    var self = this;

    var map = {
        'child': {
            update: function(options) {
                return new Child(options.data, self);
            }
        }
    }

    ko.mapping.fromJS(item, map, self);
}

var Child = function (item, parent) {
    var self = this;

    this.parent = parent;

    ko.mapping.fromJS(item, null, self);
}

JSFIDDLE

And the most knockout way - it to create custom binding that will controls descendant bindings. In this way you can extend child context with extra properties.

ko.bindingHandlers.withParent = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // Make a modified binding context, with a extra properties, and apply it to descendant elements

        ko.mapping.fromJS({
            parent: bindingContext.$rawData
        }, null,valueAccessor());

        var childBindingContext = bindingContext.createChildContext(valueAccessor, null, null);

        ko.applyBindingsToDescendants(childBindingContext, element);
        // Also tell KO *not* to bind the descendants itself, otherwise they will be bound twice
        return { controlsDescendantBindings: true };
    }
};

Model

var Parent = function (item) {
    var self = this;

    var map = {
        'child': {
            update: function(options) {
                return new Child(options.data);
            }
        }
    }

    ko.mapping.fromJS(item, map, self);
}

var Child = function (item, parent) {
    var self = this;
    ko.mapping.fromJS(item, null, self);
}

and HTML

This is <b><span data-bind="text: value"></span></b>

<div data-bind="withParent: child">
    This is <b><span data-bind="text: value"></span></b>
    <br/>
    This is <b><span data-bind="text: parent.value"></span></b> of <b><span data-bind="text: value"></span></b>
    <br/>
    <input type="button" value="Test from code" data-bind="click: test"/>
</div>

JSFIDDLE

But personaly me not like this approach, because using together with 'with', 'foreach' or 'tempalate' bindings it could cause errors like

Message: You cannot apply bindings multiple times to the same element.

Post a comment

comment list (0)

  1. No comments so far