简体   繁体   中英

How to get observable property name KnockoutJS

function Employee() {
    var self = this;
    self.name = ko.observable("John");
}

ko.bindingHandlers.test = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // implementation
    }
}

<div data-bind="test: name"></div>

Is there a way to get the observable name? not the value of the observable.

TIA.

Update:

This is the code snippet.

function ViewModel() {
    var self = this;
    $.ajax({
       type: type,
       url: url,
       success: function (data) {
           ko.mapping.fromJS(data, {} , self);
       }
    });
    self.item = ko.observable(self.my_item); 
    self.selectedItem = ko.observable();

}

ko.bindingHandlers.item = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        $el = $(element);
        var propName = allBindings().name;
        var val = ko.unwrap(valueAccessor());
        $el.attr("src", val);

        $el.click(function () {
            viewModel.selectedItem(propName); 
        });
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        $el = $(element);
        var ops = allBindings().name;
        var val = ko.unwrap(valueAccessor());
        $el.attr("src", val);
    }
};

ko.bindingHandlers.selectItem = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        $el = $(element);
        $el.attr("src", valueAccessor());
        $el.click(function () {
            bindingContext.$data.item()[ko.unwrap(bindingContext.$data.selectedItem)](valueAccessor());
        });
    }
};


<img height="25" width="25" data-bind="item: item().img1, name: 'img1'" />
<img height="20" width="20" data-bind="selectItem: '/images/myimage1.png'" />
<img height="20" width="20" data-bind="selectItem: '/images/myimage2.png'" />
<img height="20" width="20" data-bind="selectItem: '/images/myimage3.png'" />

When you click images that has selectItem the first image should replaced its src attribute. If you have better way to do this please suggest.

FYI, the properties inside items observables are link of images.

TIA.

You are getting ahead of yourself with the custom binding.

The bottom line is: You don't need a custom binding for what you want to do. It's easy - if you don't make it complicated:

 function loadImages() { // return $.get(url); // mockup Ajax response, in place of a real $.get call return $.Deferred().resolve({ items: [ {height: 20, width: 20, src: 'http://placehold.it/150/30ac17', title: 'image 1'}, {height: 20, width: 20, src: 'http://placehold.it/150/412ffd', title: 'image 2'}, {height: 20, width: 20, src: 'http://placehold.it/150/c672a0', title: 'image 3'} ] }).promise(); } function ImageList() { var self = this; // data self.items = ko.observableArray(); self.selectedItem = ko.observable(); // init loadImages().done(function (data) { ko.mapping.fromJS(data, {}, self); }); } ko.applyBindings(new ImageList()) 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script> <div data-bind="with: selectedItem"> <img data-bind="attr: {height: 25, width: 25, src: src}"> </div> <div data-bind="foreach: items"> <img data-bind="attr: {height: height, width: width, src: src}, click: $root.selectedItem" /> </div> <hr> <pre data-bind="text: ko.toJSON($root, null, 2)"></pre> 

Note how I use selectedItem as a click event handler. This is possible because in event handlers, knockout passes the relevant object (in this case, an image object from the array) as the first argument. Conveniently, observables set their value to the first argument you call them with. And presto: You have click event handler that sets the last clicked object.


EDIT

"I need multiple selected item then my items are just my context menu not just one selected item."

 function loadImages() { // return $.get(url); // mockup Ajax response, in place of a real $.get call return $.Deferred().resolve({ items: [ {height: 20, width: 20, src: 'http://placehold.it/150/30ac17', title: 'image 1'}, {height: 20, width: 20, src: 'http://placehold.it/150/412ffd', title: 'image 2'}, {height: 20, width: 20, src: 'http://placehold.it/150/c672a0', title: 'image 3'} ] }).promise(); } function ImageList() { var self = this; // data self.items = ko.observableArray(); self.selectedItems = ko.observableArray(); // init loadImages().done(function (data) { ko.mapping.fromJS(data, {}, self); }); self.selectItem = function (item) { var pos = ko.utils.arrayIndexOf(self.selectedItems(), item); if (pos === -1) self.selectedItems.push(item); }; self.deselectItem = function (item) { var pos = ko.utils.arrayIndexOf(self.selectedItems(), item); if (pos !== -1) self.selectedItems.remove(item); }; } ko.applyBindings(new ImageList()) 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script> <div data-bind="foreach: selectedItems"> <img data-bind="attr: {height: 25, width: 25, src: src}, click: $root.deselectItem"> </div> <div data-bind="foreach: items"> <img data-bind="attr: {height: height, width: width, src: src}, click: $root.selectItem" /> </div> <hr> <pre data-bind="text: ko.toJSON($root, null, 2)"></pre> 

Try something like this

view:

<div data-bind="test:name,propertyName:'name'"></div>

viewModel:

ko.bindingHandlers.test = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var propertyName = allBindings().propertyName; //property name here
        ko.bindingHandlers.text.update(element, valueAccessor);
        alert(propertyName)
    }
};

function Employee() {
    var self = this;
    self.name = ko.observable("John");
}

ko.applyBindings(new Employee());

working fiddle here

This will get you the observable name.

This converts the valueAccessor ( function(){return name } ) to a string which is then split to remove the observable name .

ko.bindingHandlers.GetObservableName = {
    init: function (element, valueAccessor) {
        var observableName = String(valueAccessor).split(' ')[1];
        alert(observableName);
    }
};

function Employee() {
    var self = this;
    self.name = ko.observable("John");
}

<div data-bind="GetObservableName: name"></div>

Here is a JSFiddle

The index of the split method in the fiddle is different to the one in the example above. The above works for me in Visual Studio 2013.

Thanks

<div  data-bind="foreach: {data: skills, as: 'skill'}" >
    <div data-bind="foreach: Object.keys(skill)" >
        <a data-bind="text: $data"></a> :   <a data-bind="text: skill[$data]"></a>
    </div>    
</div>


v = new function AppViewModel() {
    this.skills = [{rates:"sdfdcvxcsd", cat: 2, car:55}, {color:"sdfdcvxcsd", zoo: 2,boat:55}];
}

ko.applyBindings(v);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM