where to write dom manipulation code when using kn

2019-05-23 02:15发布

问题:

Hi guys i asked a question yesterday about where to code dom manipulation / animations etc when using knockout. I had previously coded this into the viewmodel and was advised this is not correct.

Ive now updated my code and created custom binding handlers as advised, however i need to call a method of my viewmodel from within the custom binding handler. Specifically when the animation completes. Ive done it like this

ko.bindingHandlers.slideUp = {
    init:function(element, valueAccessor, allBindingsAccessor, context){
        var allBindings = allBindingsAccessor();
        var parent = allBindings.parent;

        $(element).click(function(){
            if(parent.SelectedEmployee() === valueAccessor())return;

            var $PanelWrapper = $('#' + allBindings.panelName); 
            var $Bottom = parseInt($PanelWrapper.css("bottom"));

            if($Bottom === 0){
                $PanelWrapper.animate({
                    bottom:"-95"
                }, 500, function(){
                    parent.Select(valueAccessor());
                }).animate({
                    bottom:"0"
                }, 500);
            }else{
                parent.Select(valueAccessor());

                $PanelWrapper.animate({
                    bottom:"0px"
                }, 500);       
            }
        });
    }
}

and my binding is

<tbody data-bind="foreach: Emps">
            <tr data-bind="slideUp: $data, parent: $parent, panelName: 'PanelWrapper'">
                <td data-bind="text: Name"></td>
            </tr>
        </tbody>

As you can see im passing in a reference to the viewmodel and also the id of the tag i want to animate. Im just wondering if this is the correct way to do this. Is there a better way to reference the viewmodel, am i calling the method of the viewmodel correctly and is it ok to pass in the id of the html tag i want to use. It all works fine, but im keen to improve

heres a link to my fiddle

回答1:

You're now applying the binding to the element containing the employee. I think it would be better to apply the SelectedEmployee observable to the #PanelWrapper so you can show/hide it depending on the value of SelectedEmployee:

<div id="PanelWrapper" data-bind="EmployeePanel: $root.SelectedEmployee"></div>

Then your JS:

ko.bindingHandlers.EmployeePanel = {
    currentEmployee: null,
    init: function(element, valueAccessor) {
        var value = valueAccessor();
        this.setEmployee(element, ko.utils.unwrapObservable(value));
    },
    update: function(element, valueAccessor) {
        var value = valueAccessor();
        this.setEmployee(element, ko.utils.unwrapObservable(value));
    },
    setEmployee: function(element, value) {
        if (value === currentEmployee) return; // already selected employee
        this.currentEmployee = value;
        if (value) {
            $(element).fadeIn(); // show and populate the panel here
        } else {
            $(element).fadeOut(); // hide the panel here
        }
    }
};

So now your employee row will look like this:

<tr data-bind="click: $root.OnEmployeeClick">

And your ViewModel:

self.OnEmployeeClick = function(employee) { self.SelectedEmployee(employee); };


标签: knockout.js