Вопрос

i am using http://aehlke.github.com/tag-it/ in my code how to bind with viewmodel

html

<ul data-bind='jqueryui: "tagit",foreach: Tags' >
            <li class="tagit-choice ui-widget-content ui-state-default ui-corner-all" data-bind='with: $data'>
                <span class="tagit-label" data-bind='text: $data'></span>
                <a class="tagit-close">
                    <span class="text-icon">&times;</span>
                    <span class="ui-icon ui-icon-close"></span>
                </a>
                <input type="hidden" name="item[tags][]" data-bind='value: $data'  style="display: none;">
            </li>
            </ul>

Js code

function AppViewModel() {
var self = this;

function Tag(data) {
            this.Name = data;
        }

self.Tags = ko.observableArray([
            new Tag('red'),
            new Tag('blue'),
            new Tag('green')
        ]);
 }

// Activates knockout.js
ko.applyBindings(new AppViewModel());

Thanks in advance for your assistance!

Это было полезно?

Решение 4

thanks Cedric no need to write custom binder

i solve this way link

$("#mytags").tagit({
 availableTags: JSON.parse(ko.toJSON(_.pluck(AppViewModel.Tags, 'Name'))),
 onTagAdded: function (event, tagval) {
                    //on every add add with id if tag exist in system
                    var newtag = $(tagval).children('span.tagit-label').html();
                    var temp = _.find(AppViewModel.Tags, function (item) { return item.Name() == newtag; });
                    if (temp) {
                            AppViewModel().SelectedTags.push( Tag({ 'Id': temp.Id(), "Name": newtag} ));
                    }
                    else {
                            AppViewModel().SelectedTags.push( Tag({ "Name": newtag} ));
                    }

                },
onTagRemoved: function (event, tagval) {
                    // do something special
                    var tempTag = $(tagval).children('span.tagit-label').html();
                    AppViewModel().SelectedTags.remove(_.find(SelectedTags(), function (item) { return item.Name == tempTag; }));
                }});

Другие советы

Here's a another binding handler for knockout based on Robert Wagner's answer, since i didnt feel that it was dynamic enough:

ko.bindingHandlers.tagit = {
//https://github.com/aehlke/tag-it
init: function (element, valueAccessor, allBindingsAccessor) {
    var bind = function () {
        valueAccessor().tags($(element).tagit("assignedTags"));
    };

    var options = $.extend({
        allowSpaces: false,
        caseSensitive: false,
        showAutocompleteOnFocus: true,
        afterTagAdded: function(t,s) { bind(); },
        afterTagRemoved: function(t,s) { bind(); },
        placeholderText: "",
        preprocessTag: function () { },
        beforeTagAdded: function (evt, tag) {
            if (tag.tagLabel.length == 0 || tag.tagLabel.toLowerCase() === options.placeholderText.toLowerCase()) {
                return false;
            }
            return true;
        }
    }, valueAccessor().options || {});

    var tags = valueAccessor()["autocomplete"];
    if (tags)
        $.extend(options, {
            autocomplete: $.extend({ source: tags.source, delay: 0, minLength: 0 },tags)
        });

    $(element).tagit(options);
},
update: function (element, valueAccessor) {
    var value = ko.utils.unwrapObservable(valueAccessor());
    var tags = value.tags();
    $(element).tagit("removeAll");
    for (var x = 0; x < tags.length; x++) {
        $(element).tagit("createTag", tags[x]);
    }
}
};

My preprocess and autocompleter functions:

self.TagAutocompleter = function (d, ds) {
    DataMethod.postData("tag/autocomplete", d, function (data) {
        ds(ko.utils.arrayMap(data, function (t) { return t.Tag; }));
    });
};

self.TagProcessor = function (tag) {
    return tag.toLowerCase().replace("#", '');
};

And use in html:

<ul data-bind="tagit:{tags:Tags, autocomplete:{source:TagAutocompleter, delay:250, minLength: 2}, options:{preprocessTag: TagProcessor}}">
</ul>

Here is a custom binding https://gist.github.com/droyad/6136446

ko.bindingHandlers.tags = {
    init: function (element, valueAccessor, allBindingsAccessor) {

        var bind = function() {
            var observable = valueAccessor();
            observable($(element).tagit("assignedTags").join(','));
        };

        var options = {
            allowSpaces: true,
            caseSensitive: false,
            showAutocompleteOnFocus: true,
            afterTagAdded: bind,
            afterTagRemoved: bind
        };

        var tags = allBindingsAccessor()["tagsSource"];
        if (tags)
            $.extend(options, {                
                autocomplete: { source: tags, delay: 0, minLength: 0 }
            });

        $(element).tagit(options);
        $(element).data('uiTagit').tagInput.css("width", "50px");
    },
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var tags = value.split(',');
        $(element).tagit("removeAll");
        for (var x = 0; x < tags.length; x++) {
            $(element).tagit("createTag", tags[x]);
        }
    }
}

I write a simple fiddle where it's work. It's construct component with de tag list. Fiddle

But it's not a two ways binding. If you wan't to do that i advise you to create a custom binder where it call the knockout's foreach model binder . See information to Custom model binders

On the init function, you need to subscibe to tags changes in knockout observableArray for update the control. And you need to subscribe to onTagAdded event and onTagRemoved event.

There is a sample code where i extend the foreach component:

ko.bindingHandlers.extendForeach = {
    makeForeachValueAccessor: function (valueAccessor) {
         return function () {

            if ((!bindingValue) || typeof bindingValue.length == "number"){
                bindingValue = {
                    data : bindingValue
                }
            }

            return {
                'data': bindingValue['data'],
                'afterAdd': bindingValue['afterAdd'],
                'beforeRemove': bindingValue['beforeRemove'],
                'afterRender': bindingValue['afterRender'],
            };
        };
    },

    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var newValAccess = ko.bindingHandlers.extendForeach.makeForeachValueAccessor(valueAccessor);
        return ko.bindingHandlers.foreach.init(element, newValAccess, allBindingsAccessor, viewModel, bindingContext);
    },

    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var newValAccess = ko.bindingHandlers.extendForeach.makeForeachValueAccessor(valueAccessor);
        return ko.bindingHandlers.foreach.update(element, newValAccess, allBindingsAccessor, viewModel, bindingContext);
    }
}

I hope this help you.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top