Вопрос

I'm attempting to create an angular.js directive from James Smith's tokenInput Jquery plugin: http://loopj.com/jquery-tokeninput

Here is what I have so far:

antdna = angular.module('Communication', []);

antdna.factory('autoCompleteService', [function() {
    return {
      getSource: function() {
      return [{"id":1, "name":"John Doe"}, {"id":2, "name":"Jane Smith"}];
    }
  }
}]);

antdna.directive('autoComplete', function(autoCompleteService) {
    return {
        restrict: 'A',
        link: function(scope, elem) {
            elem.tokenInput(autoCompleteService.getSource(), {
                crossDomain:false,
                theme: "facebook",
                hintText: "Enter User Name",

                preventDuplicates: true
            });
            }
    };
});

With the following markup:

<input type="text" name="recipient" ng-model="conversation.recipients" class="messageComposeTextField" auto-complete placeholder="To :" required />

TokenInput works perfectly but my issue is that I cannot bind to the model.

{{conversation.recipients}} 

is blank.

The tokenInput plugin generates it's own markup using list elements (ul and li). So upon inspecting the element I get:

<ul class="token-input-list-facebook">
  <li class="token-input-token-facebook"><p>John Doe</p><span class="token-input-delete-token-facebook">×</span></li><li class="token-input-input-token-facebook"><input type="text" autocomplete="off" autocapitalize="off" id="token-input-" style="outline: none; width: 30px;"><tester style="position: absolute; top: -9999px; left: -9999px; width: auto; font-size: 12px; font-family: Ubuntu, 'Ubuntu Beta', UbuntuBeta, Ubuntu, 'Bitstream Vera Sans', 'DejaVu Sans', Tahoma, sans-serif; font-weight: 400; letter-spacing: 0px; white-space: nowrap;"></tester>    </li>
</ul>

<input type="text" name="recipient" ng-model="conversation.recipients" class="messageComposeTextField ng-pristine ng-invalid ng-invalid-required" auto-complete="" placeholder="To :" required="" style="display: none;">

Notice that the generated tokenInput markup is not part of the directive. So the real question here is how do I encapsulate a jquery plugin that generates its own markup within an angularjs directive?

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

Решение 2

I suggest you to use ui-select2 ready to use directive for similar functionality @ https://github.com/angular-ui/ui-select2, it provides "simple tagging mode" similar to your requirement

Check the new example. The old example can be found here.

$scope.tagsSelection = [
    { "id": "01", "text": "Perl" },
    { "id": "03", "text": "JavaScript" }
];       

$timeout(function(){
    $scope.tagsSelection.push({ 'id': '02', 'text': 'Java' });
}, 3000);

$scope.tagData = [
    {
        "id": "01",
        "text": "Perl"
    },
    {
        "id": "02",
        "text": "Java"
    },
    {
        "id": "03",
        "text": "JavaScript"
    },
    {
        "id": "04",
        "text": "Scala"
    }
];

$scope.tagAllOptions = {
    multiple: true,
    data: $scope.tagData
};

You can check details for options and documentation at: http://ivaynberg.github.io/select2/

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

Following up @JqueryGuru suggestion, perhaps you'd be interested in taking a look at a tags input directive I've implemented recently: ngTagsInput. It's 100% Angular code and has several configuration options. You can see some demos here.

I had similar issues and while the alternate plugin and Angular own tag directives are very interesting, I was not able to change the token-input plugin because of some project requirements, therefore I added model update logic into the Add/Delete configuration variables of Token Input plugin.

The Code:

vehicleModule.directive('tokenInput', function ($rootScope,$parse, $http){
return {
    restrict: 'A',
    link: function(scope, elem, attr, ctrl) {
        var prepopMailsJson = getElementsAsJson(elem.attr('value'));            
        elem.tokenInput(applicationRootUrl +"rest/firmwareManager/getAvailableVehicles", {
            prePopulate: prepopMailsJson,
            theme: "facebook",
            minChars: 2,
            resultsLimit: 12,
            propertyToSearch: "id",
            resultsFormatter: function(item){ 
                var name = "";
                if(typeof(item.name) != 'undefined' && item.name != null){
                    name = item.name;
                }
                return "<li>" + "<div style='display: inline-block; padding-left: 10px;'><div class='id'>" + item.id + "</div></div></li>"; 
            },
            tokenFormatter: function(item) { 
                return "<li><p>" + item.id + "</p></li>"; 
            },
            hintText: vehicleTokenInputTranslation.hintText,
            noResultsText: vehicleTokenInputTranslation.noResultsText,
            searchingText: vehicleTokenInputTranslation.searchingText,
            preventDuplicates: true,
            queryParam: "partialName",
            tokenLimit: 1,
            onAdd : function(item){                 
                scope.vehicleId = item.id;
            },
            onDelete : function(item){
                scope.vehicleId = '';
                scope.$apply();
            }
        });

    }
};


});

This way, you only need to use the token-input directive in your input element and it will work. This can be made even more generic by passing the model variable name in the attr. I hope this code is useful to people that have issues integrating JqueryUI Token-Input and AngularJS.

For people who are required to use the loopj token-input for whatever reason, this gist worked perfectly for me. I found it to be kind of cryptic though, since I'm not very experienced with Angular and he only had 2 comments, so here's what I've figured out about how to use it.

You include the top level jquery module like:

angular.module('myModule', ['jquery'])

In the html you have:

<input token-input="source">

In the javascript you have:

$scope.source = {/* data */};
$scope.tokenInput = {/* options */}

If you want to have several with different options, it looks like you could also do something like:

<input id="id" token-input="source">
$scope.source = {/* data */};
$scope.tokenInput_id = {/* options */}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top