Knockout.js get dom object associated with data

前端 未结 5 2037
别那么骄傲
别那么骄傲 2020-12-23 13:28

I\'m working with knockout.js to build dynamic lists and I\'m trying to figure out how I can get the DOM object associated with an object in my observable array. Specifical

相关标签:
5条回答
  • 2020-12-23 13:59

    The $(event.target) solution is good if it is related to an already occurring event in which the item's DOM element is at target. But sometimes you don't have the targeted item because there is no event (for example - you want to scroll a list to an item that was not gestured by the user).

    In such case you can give the item's DOM element id attribute a unique value that contains the item id:

    <li data-bind="attr: {id: 'item_' + id}">
    

    and then getDomObject() looks like:

    getDomObject = function(item) { return $("#item_" + item.id); }
    
    0 讨论(0)
  • 2020-12-23 14:01

    My solution (valid for "value" binding)

     ko.bindingHandlers.value.preprocess = function(val, name, cb) {
        /* every time I set a data-bind="value: xxxx" with an 
         * observable xxxx add also a data-bind="domElement: xxxx" */
        cb('domElement', val );
        return val;
    }
    
    ko.bindingHandlers.domElement = {
        /* For each data-bind="domElement: xxxx" add an extension "element" */
        init: function (element, valueAccessor, allBindingsAccessor, viewModel) { 
          valueAccessor().extend({element: element });
        }
      };
    
    ko.extenders.element = function (target, element) {
        /* element extension add el and $el to observable xxxx */
        target.el = element;
        target.$el = $(element);
    } 
    

    Now you have yourobservable.$el and yourobservable.el which bind to jquery and DOM element.

    0 讨论(0)
  • 2020-12-23 14:12

    To add yet a 3rd option, also for cases where you don't have an event to work with (if you have an event, the accepted answer is best/optimized).

    Create a custom binding such as:

    ko.bindingHandlers.scrollTo = {
        update: function(element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor());
            if (value) {
                var scrollParent = $(element).closest("div");
                var newTop = $(element).position().top + scrollParent.scrollTop();
                scrollParent.scrollTop(newTop);
            }
        }
    };
    

    usage is as follows:

    <li data-bind="scrollTo: $parent.scrollTo() && $parent.scrollTo().id == id">
    

    In the above case, $parent is my View Model. I have an observable object which contains a unique ID. Anytime I set that scrollTo() object, the list scrolls to that item.

    Note that my code assumes the parent DIV of the LI has the scrollbar (overflow:auto/scroll). You can adjust for your needs, possibly use a class on the parent and use that for your jQuery selector, or to make very flexible you could pass in the selector via your data-bind options... for me, this was enough, as I always use divs for my scrollable sections.

    0 讨论(0)
  • 2020-12-23 14:12

    I had a similar problem. I come up with a solution resembling Backbone.js use of el and $el references.

    in your ViewModel:

    var myViewModel = function(){
      var self = this;
    
      //html element
      self.el = ko.observable();
    
      //jquery wrapped version
      self.$el = ko.observable();
    }
    

    in html (for example list element):

    <!-- left side is the name of the handler, right side is name of the observable -->
    <li class="myclass" data-bind="el: el, $el: $el"></li>
    

    in bindingHandlers (showing all possible arguments to init):

    ko.bindingHandlers.el = {
      init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var value = valueAccessor();
        //assign value to observable (we specified in html)
        value(element);
      }
    };
    
    ko.bindingHandlers.$el = {
      init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var value = valueAccessor();
        //here we first create a jQuery object by using $(myelem)
        //before updating observable value
        value($(element).first());
      }
    };
    

    For example, then you can use $el like:

    var myViewModel = function(){
      var self = this;
    
      //plain DOM element reference
      self.el = ko.observable();
    
      //jquery object reference
      self.$el = ko.observable();
    
      self.myFunction = function() {
        console.log(self.$el().html());
        self.$el().addClass("myCssClass");
      }
    }
    

    Hope this helps!

    0 讨论(0)
  • 2020-12-23 14:25

    Event handlers like click get passed two arguments. That is

    1. the item that this event belongs to - like the entry of an observable array that you're rendering with the foreach binding ("Item" in your case).

    2. And, an event object, that provides you with more information about the actual event. This object contains the DOM element that got clicked on (key "target"):

      getDomObject = function(item, event) {
          var $this = $(event.target);
          // ...
      }
      

    Just a note: Don't mix knockout and native jQuery DOM manipulations - if you can achieve the same result with clever knockout bindings, I would recommend going with that.

    And here is a simple demo: http://jsfiddle.net/KLK9Z/213/

    var Item = function(color) {
      this.color = String(color);
      this.setTextColor = function(item, event) {
        $(event.target).css('background', color);
      };
    };
    
    ko.applyBindings(new function() {
      this.Items = ko.observableArray([
        new Item('red'),
        new Item('blue'),
        new Item('green')
      ]);
    }());
    li {
      padding: 2px 10px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.0.0/knockout-min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <ul data-bind="foreach: Items">
      <li>
        <button data-bind="click: setTextColor, text: 'Color: ' + color"></button>
      </li>
    </ul>

    0 讨论(0)
提交回复
热议问题