4

I am trying to use AngularJS to provide a toggable dropdown list, where the selection of various options will trigger different lists. ng-switch seemed like the right way to do it, but my ng-model is not binding while inside the ng-switch. The binding works fine if I do not use ng-switch, but I do not know how to toggle my dropdown lists if that's the case. What could be the issue here?

jsFiddle: http://jsfiddle.net/tanweihao88/LUzXT/3/

HTML:

<select ng-model="periodRangeModel" ng-options="item for item in items"></select>
<div ng-switch on="periodRangeModel">
    <span ng-switch-when="Month"><period-selector items="monthOptions" ng-model="periodModel"></period-selector></span>
    <span ng-switch-when="Quarter"><period-selector items="quarterOptions" ng-model="periodModel"></period-selector></span>
    <br>
</div>

JS:

angular.module('myApp', [])
.controller("MyCtrl", function($scope) {
    $scope.items = ['Month', 'Quarter'];
    $scope.periodRangeModel = "Month";
    $scope.quarterOptions = ["Jan-Mar", "Apr-Jun", "Jul-Sept", "Oct-Dec"];
    $scope.monthOptions = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
    $scope.periodModel = $scope.monthOptions[0];
})
.directive('periodSelector', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: { items: '=', ngModel: '='},
        template: "<span><select ng-options='period for period in items' ng-model='ngModel'></select></span>"
    }
});
Wei Hao
  • 2,756
  • 9
  • 27
  • 40

1 Answers1

6

The main reason the binding does not work as intended is ng-switch creates a new scope and when binding to a string primitive the original periodModel isn't being updated as you expect (since the new scope's periodModel is being updated).

This question has a lot more detail on what's going on behind the scenes and you can check out the Angular Batarang Chrome Extension to visually see the various scopes at play.

You can get around it by binding to an object value like in this updated fiddle. The main changes are:

1) Change periodModel to an object and set a property (in this example it's called value)

$scope.periodModel = {
    value: $scope.monthOptions[0]
};

2) Change any binding code to access periodModel.value instead of periodModel

<period-selector items="monthOptions" ng-model="periodModel.value"></period-selector>

Model: {{periodModel.value}} (this is supposed to change)
Community
  • 1
  • 1
Gloopy
  • 37,767
  • 15
  • 103
  • 71
  • I see! Thank you! Do you know if there is any way I can recompile the `template`? I have some custom template code that doesn't compile once I toggle to another dropdown list. – Wei Hao Jun 04 '13 at 03:46
  • You can recompile html with a different angular html template (see [these docs](http://docs.angularjs.org/api/ng.$compile)) but it might be overkill for what you're trying to do. Take a look at a [modified version](http://jsfiddle.net/LUzXT/5/) of your original example without creating directives in case you can bypass custom directives. If you create a fiddle example I (or someone else) can try and help. – Gloopy Jun 04 '13 at 04:09
  • I was unable to create a fiddle as I'm using third party libraries. In essence, I'm using [bootstrap-select](http://silviomoreto.github.io/bootstrap-select/) which uses both css and js to style the dropdown list. But once I toggle the list, the styling is gone. – Wei Hao Jun 04 '13 at 06:14
  • I would trying calling the [render()](http://silviomoreto.github.io/bootstrap-select/#render) method on your select element after the dropdown contents are updated by angular on toggle. [This post](http://stackoverflow.com/questions/12304291/angularjs-how-to-run-additional-code-after-angularjs-has-rendered-a-template) may help with figuring out when to call `render` though I'd test it manually (like in an ng-click event or in the console) first to make sure render is working for you. Hope this helps! – Gloopy Jun 04 '13 at 07:21
  • It didn't seem to work, but anyway I got around it by re-initializing the javascript. Thanks! – Wei Hao Jun 04 '13 at 09:01