How to use tagit with knockout
Asked Answered
J

4

5

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!

Jesus answered 12/10, 2012 at 8:33 Comment(0)
J
0

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; }));
                }});
Jesus answered 31/10, 2012 at 11:6 Comment(0)
B
8

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>
Bertsche answered 6/1, 2014 at 10:56 Comment(3)
Also I Fixed an error in the update part, so it can use data that is in the observable from the startBertsche
Can you include a code snippet for TagAutocompleter and TagProcessor?Russelrussell
I've updated the original answer with those + a minor update :)Bertsche
C
4

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]);
        }
    }
}
Coats answered 2/8, 2013 at 0:5 Comment(0)
L
1

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.

Liveried answered 12/10, 2012 at 10:32 Comment(0)
J
0

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; }));
                }});
Jesus answered 31/10, 2012 at 11:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.