简体   繁体   中英

How Do I Call A Function from ViewModel inside bindingHandler

I have a method inside my viewModel that gets calls an ajax get method to fetch all of the items. This all works perfect. I then have a ko.bindingHandler that is used to inline upload images via ajaxSubmit. This also works, but the issue is I have to duplicate code that fetches all of the items inside the bindingHandler that uploads the images or else the image wont update once uploaded. Refreshing the page fixes the issue but I want to have the view auto refresh with the new image. So the real question is it possible to call a function from the viewModel inside a bindingHandler? Any help would be greatly appreciated!

BindingHandler:

ko.bindingHandlers.imageInLineUpload = {
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var options = ko.utils.unwrapObservable(valueAccessor()),
            property = ko.utils.unwrapObservable(options.property);

        $(element).change(function () {
            if (element.files.length) {
                if ((element.files[0].type === "image/png") || (element.files[0].type === "image/jpeg")) {
                    var $this = $(this);
                    $(element.form).ajaxSubmit({
                        url: $.API.url + "XYZ",
                        type: "POST",
                        dataType: "text",
                        success: function (data) {
                            toastr.success('Upload Successful.');
                            var viewModel= new MyViewModel ();
                            viewModel.GetObjects();
                        },
                        error: function (jqXHR, textStatus, errorThrown) {
                            toastr.error('Upload Failed. Please Try again!');
                        }
                    });
                }
                else {
                    toastr.error('Upload Failed. PNG and JPEG are the only supported formats.');
                }
            }
        });
    }
};

ViewModel:

var MyViewModel = function () {     
   var self = this;     
   self.xyz = ko.observable("");    
   self.xyz  = ko.observable(""); 
   self.xyz = ko.observable("");

   self.GetObjects= function () {       
   // Ajax call to fetch objects.

   } 
   self.GetObjects();
};

ko.applyBindings(new MyViewModel ());

One method that I have used in the past is to pass a reference to the function into the binding handler as an option similar to how we use callbacks elsewhere -

<div data-bind="imageInLineUpload: someObservable, imageILUOptions: { callback: myFunction }"></div>

and in your binding handler you can access the function like this -

ko.bindingHandlers.imageInLineUpload = {
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var options = ko.utils.unwrapObservable(allBindingsAccessor).imageILUOptions;
        var callback = options.callback;

        // do something
        callback(someVar);

This allows you to pass any function into the binding and use it as a callback inside of it. It's not a perfect solution but should get you what you need.

There's a couple ways to do this. The way to literally "call a viewModel function from the bindinghandler" is to do:

var viewModel = ko.dataFor(element);
viewModel.GetObjects()

This will work, but it's a pretty mediocre solution; it pretty much tightly couples your binding handler to this one specific viewModel and it's an implicit dependency; the bindingHandler API doesn't make it clear that this function is needed.


Another way (in my opinion, a better way) is to pass the function into the bindingHandler as an options argument:

<div data-bind="imageInLineUpload: {getImagesCallback: GetObjects}"></div>

In the bindinghandler:

var options = ko.utils.unwrapObservable(valueAccessor()),
    getImagesCallback =  options.getImagesCallback;

getImagesCallback();

(This is similar to PW Kad's answer, but I think specifying a separate bindingKey to provide options to a different bindinghandler is a bad idea for a required argument, and is a pretty ugly way to do knockout bindinghandlers, compared to just passing an object to the current binding hander)


But really, if your binding handler is doing asyncronous calls, I think you're need to restructure something. Bindinghandlers, in my opinion, should be doing view logic only, not dealing with AJAX which should be in the ViewModel.

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