dan
dan

Reputation: 532

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.

Upvotes: 1

Views: 3276

Answers (4)

bjhamltn
bjhamltn

Reputation: 410

<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);

Upvotes: 1

Tomalak
Tomalak

Reputation: 338128

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>

Upvotes: 1

shammelburg
shammelburg

Reputation: 7308

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

Upvotes: 0

super cool
super cool

Reputation: 6045

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

Upvotes: 0

Related Questions