2012-10-01 5 views
19

Je développe actuellement une application web qui utilise twitter-bootstrap et Angularjs en bonne harmonie. Cependant, j'ai des problèmes avec le typeahead et je l'utilise comme un ng-modèle.Utilisation de Bootstrap typeahead avec Angular

Tout fonctionne correctement lors de la saisie, mais lorsque je sélectionne un élément (une suggestion), la valeur ne s'affiche dans le contrôleur angulaire que si je change la valeur de la zone de texte après la sélection d'une valeur. Type -> Sélectionner -> Type fonctionne. Type -> Sélectionner ne fonctionne pas.

HTML:

<form ng-submit="addAssignment(assignName)"> 
    <div class="input-append"> 
    <input type="text" placeholder="Type a name" ng-model="assignName" ng-change="dostuff()" data-provide="typeahead" data-source="{{ teamNames }}"> 
    <button class="btn" type="submit">Add</button> 
</div> 
</form> 

Code angulaire:

$scope.addAssignment = function(name) { 
    alert(name); 
    return; 
} 

J'ai ajouté une fonction ng changement juste pour vérifier si la valeur du modèle est modifié. Il est uniquement modifié lors de la saisie manuelle, et NON lorsqu'une valeur est sélectionnée dans la liste qui apparaît sur la fonction typeahead.

J'apprécie toute réponse qui pourrait aider à résoudre ce problème. Merci!

+0

a cette question été résolu? –

+0

Malheureusement, non ... –

Répondre

3

Eh bien, j'ai créé une solution de contournement sale. Sur la base de l'exemple situé ici: https://groups.google.com/forum/#!topic/angular/FqIqrs-IR0w/discussion, j'ai créé un nouveau module pour le contrôle typeahead:

angular.module('storageApp', []).directive('typeahead', function() { 
return { 
    restrict:'E', 
    replace:true, 
    scope:{ 
     model:'=', 
     source:'&' 
    }, 
    template:'<input type="text" ng-model="model"/>', 
    link:function (scope, element, attrs) { 
     console.log(scope.source); 
     $(element).typeahead({ 
      source:scope.source, 
      updater:function (item) { 
       scope.$apply(read(item)); 
       return item; 
      } 
     }); 

     function read(value) { 
      scope.model = value; 
     } 
    } // end link function 
}; // end return 
}); // end angular function 

J'ai eu quelques problèmes avec la liaison de données, les options d'auto-remplissage sont recueillies à partir d'un contrôle angulaire, et je devais le problème que le contrôle a été créé avant que cette information était prête. Par conséquent, j'ai ajouté un attribut html (datasource) au contrôle typeahead, et mis en place une fonction $ observe dans le constructeur. Je pense que c'est une solution sale, donc si quelqu'un a une meilleure idée, je suis la bienvenue pour l'entendre :). Le bug est décrit ici: https://github.com/angular/angular.js/issues/1284

+0

Vous n'avez pas besoin de $ (élément). Quoi que Vous pouvez simplement element.whatever –

0

Voici une autre méthode que j'ai utilisée. C'est sale aussi. Ce code peut être supprimé dans votre contrôleur.

$('#id_of_your_typeahead_input').change(function(event){ 
    $scope.$apply(function(scope){ 
    scope.your_ng_model = event.target.value; 
    }); 
    $scope.your_ng_click_function(); 
}); 
+0

Bien que sale, cela sonne mieux. – Hengjie

0

Ceci est basé sur la mise en œuvre de @ zgohr

$('#your-input-id-here').change((event)-> 
    angular.element("#your-input-id-here").scope().$apply((scope)-> 
    scope.your_ng_model = event.target.value 
) 
) 
21

Je suggère de vérifier la directive typeahead du référentiel AngularUI/boostrap: http://angular-ui.github.com/bootstrap/

Il est natif implémentation dans AngularJS pur donc il ne nécessite aucune dépendance de tiers.De plus, il est très bien intégré à l'écosystème AngularJS car: * utilise une syntaxe concise connue de la directive select * comprend les promesses AngularJS pour que les résultats puissent être récupérés dynamiquement en utilisant $http avec un minimum d'effort.

+0

vous utiliserez probablement angular-strap car il supporte la dernière version de angularjs;) – genuinefafa

0

Une autre alternative

En HTML

<form ng-submit="submitRegion()"> 
     <input type="text" ng-model="currentRegion" id="region-typeahead" data-source="{{ defaultRegions }}" data-provide="typeahead"/> 
     <button type="submit" class="btn">Add</button> 
    </form> 

Dans votre contrôleur

$scope.defaultRegions = ["Afghanistan", "Australia", "Bahrain", "New Zealand" ]; 

    $scope.submitRegion = function(){ 
     $scope.currentRegion = $('#region-typeahead').val(); 
     $scope.addRegion(); //your add or click function you defined 
     $scope.currentRegion = ''; //clear 
    } 
9

J'ai fait cette mise en œuvre typeahead native en se fondant uniquement sur (css et d'amorçage pour le style) angulaire, pourrait aider Quelqu'un cherche comment faire cela.

Demo ici: https://jsfiddle.net/bh29tesc/

directive angulaire:

angular.module('app'). 
directive('typeahead', ['$compile', '$timeout', function($compile, $timeout) { 
    return { 
     restrict: 'A', 
     transclude: true, 
     scope: { 
      ngModel: '=', 
      typeahead: '=', 
      typeaheadCallback: "=" 
     }, 
     link: function(scope, elem, attrs) { 
      var template = '<div class="dropdown"><ul class="dropdown-menu" style="display:block;" ng-hide="!ngModel.length || !filitered.length || selected"><li ng-repeat="item in filitered = (typeahead | filter:{name:ngModel} | limitTo:5) track by $index" ng-click="click(item)" style="cursor:pointer" ng-class="{active:$index==active}" ng-mouseenter="mouseenter($index)"><a>{{item.name}}</a></li></ul></div>' 

      elem.bind('blur', function() { 
       $timeout(function() { 
        scope.selected = true 
       }, 100) 
      }) 

      elem.bind("keydown", function($event) { 
       if($event.keyCode == 38 && scope.active > 0) { // arrow up 
        scope.active-- 
        scope.$digest() 
       } else if($event.keyCode == 40 && scope.active < scope.filitered.length - 1) { // arrow down 
        scope.active++ 
        scope.$digest() 
       } else if($event.keyCode == 13) { // enter 
        scope.$apply(function() { 
         scope.click(scope.filitered[scope.active]) 
        }) 
       } 
      }) 

      scope.click = function(item) { 
       scope.ngModel = item.name 
       scope.selected = item 
       if(scope.typeaheadCallback) { 
        scope.typeaheadCallback(item) 
       } 
       elem[0].blur() 
      } 

      scope.mouseenter = function($index) { 
       scope.active = $index 
      } 

      scope.$watch('ngModel', function(input) { 
       if(scope.selected && scope.selected.name == input) { 
        return 
       } 

       scope.active = 0 
       scope.selected = false 

       // if we have an exact match and there is only one item in the list, automatically select it 
       if(input && scope.filitered.length == 1 && scope.filitered[0].name.toLowerCase() == input.toLowerCase()) { 
        scope.click(scope.filitered[0]) 
       } 
      }) 

      elem.after($compile(template)(scope)) 
     } 
    } 
}]); 

Utilisation:

<input class="form-control" type="text" autocomplete="false" ng-model="input" placeholder="Start typing a country" typeahead="countries" typeahead-callback="callback" /> 
+0

sur le violon, quand vous en sélectionnez un, il ne l'attribue pas au ngmodel – gdubs

+0

il affecte item.name à ngModel. pour obtenir l'objet entier, si c'est ce que vous voulez dire, utilisez le rappel. Ou modifiez-le pour affecter ce dont vous avez besoin – ropsnou

Questions connexes