3

Im working with knockout.js and select2 plugin.
Im trying to change the select2 ajax url based on a value of an observable.
for example if based on some selection i do ajax call to 1 url or another. Here is a sample code:

<input type="hidden" data-bind="combobox: { optionsText: 'Name', optionsValue: 'ID', optionsCaption: 'Избери...', sourceUrl: partnerUrl }, value: ApplyToSubject" id="ApplyToSubject" name="ApplyToSubject">

This is how the sourceUrl: partnerUrl is retrieved:

self.partnerUrl = ko.computed(function () {
        var value = "";
        if (something)
        {
            value = apiUrls.customer;
        }
        else if (something else)
        {
            value = apiUrls.vendor;
        }
        else if(or another thing)
        {
            value = apiUrls.employee;
        }
        return value;
    });

I work with custom binding. Here is the code for it:

// documentation http://ivaynberg.github.io/select2/
ko.bindingHandlers.combobox = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var obj = valueAccessor(),
            allBindings = allBindingsAccessor();
        var optionsText = ko.utils.unwrapObservable(obj.optionsText);
        var optionsValue = ko.utils.unwrapObservable(obj.optionsValue);
        var sourceUrl = ko.utils.unwrapObservable(obj.sourceUrl);
        var selectedID = ko.utils.unwrapObservable(allBindings.value);
        var model = obj.model;
        var unwrapped = ko.utils.unwrapObservable(obj.model);

        $(element).select2({
            minimumInputLength: 3,
            formatResult: function formatResult(result) {
                return result.text;
            },
            data: function (model) {
                return { id: unwrapped[optionsValue](), text: unwrapped[optionsText](), data: unwrapped }
            },
            initSelection: function (element, callback) {
                if (unwrapped && selectedID !== "") {
                    callback({ id: unwrapped[optionsValue](), text: unwrapped[optionsText](), data: unwrapped });
                }
            },
            ajax: {
                quietMillis: 500,
                url: subdirUrl + sourceUrl,
                dataType: 'json',
                data: function (search, page) {
                    return {
                        page: page,
                        search: search
                    };
                },
                results: function (data) {
                    var result = [];
                    $.each(data.list, function (key, value) {
                        result.push({ id: value[optionsValue], text: value[optionsText], data: value });
                    });
                    var more = data.paging.currentPage < data.paging.pageCount;
                    return { results: result, more: more };
                }
            }
        });
        $(element).on('select2-selected', function (eventData) {
            if (eventData.choice) {
                // item selected
                var selectedItem = eventData.choice.data;
                var selectedId = eventData.choice.id;
                model(selectedItem);
            }
            else {
                model(undefined);
            }
        });

        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            $(element).select2('destroy');
        });
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var obj = valueAccessor(),
            allBindings = allBindingsAccessor();
        var selectedID = ko.utils.unwrapObservable(allBindings.value);
        $(element).val(selectedID).trigger('change');
    }
};

It works for url's that dont change, but for urls that need to update, i cant make it work. (it seems like its keeping the first url that was passed (sourceUrl).

3
  • ko.computed are only triggered when a change happens to any observable used in the logic in the method. So if none of your something, something else, etc. are observables or computed themselves, it will only ever return one value. Commented Aug 27, 2014 at 11:03
  • In the If statements, the variables are observables, and the ko.computed variable is updated each time the inner value changes. But the custom binding ajax url value, seems like its keeping the initial value Commented Aug 27, 2014 at 14:05
  • You should consider putting it up on jsfiddle. Commented Aug 27, 2014 at 14:34

1 Answer 1

5

I've finally managed to solve this one.

From what i could read from the select2 documentation, you should pass string or function to ajax url parameter. So this is what i've done
I've written a function that returns value of the observable (which is the url):

self.returnUrl = function () {
    return self.dynamicUrl();
};

And then i pass that function to my custom binding options:

<input data-bind="combobox: { ... sourceUrl: $data.returnUrl }, value: ApplyToSubject" type="hidden" >

Then the custom binding works the same as in the code in the question, with a small change:

...
ajax: {
     url: sourceUrl <- this is the returnUrl function
...
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.