1

$scope seems to be missing binding properties for a text box typeahead and a select list. Here is a fiddle showing the behavior I want: http://jsfiddle.net/langtonr/h4MKa/1/ You can add and remove salesmen as desired. The $scope is binding correctly to $scope.salesmanEntry (the salesman selected in the typeahead) and $scope.selectedSalesmen (salesmen that have been selected in the list box).

This same code I have copied and pasted into my project and it does not work. I am using all the same library references. It seems scope just doesn't work for these 2 variables. $scope.salesmanEntry and $scope.selectedSalesmen are always undefined. My full controller code is below. What could possibly be interfering with my $scope?

I'm outputting the following on my view:

<div>{{salesmanEntry.id}} {{salesmanEntry.displayName}}</div>

My view always shows these correctly, so when I have typed a salesman, it shows up, yet when I get to my controller code, $scope.salesmanEntry is always undefined. It exhibits the same behavior with $scope.selectedSalesmen. I can output to the screen by using an ng-repeat on selectedSalesmen, yet in my controller $scope.selectedSalesmen is always undefined.

manageProductsModule.controller('productDetailCtrl', [
    'productSvc', 'equipmentOptionSvc', 'salesmanSvc', '$scope', function (productSvc, equipmentOptionSvc, salesmanSvc, $scope) {
        $scope.loadingProduct = false;
        $scope.product = {
            secureUsers: [],
            options: [],
            priceHistory: []
        };
        $scope.addedSalesmen = [];
        $scope.allSalesmen = [
    { id: 1, displayName: "Smith, John" },
    { id: 2, displayName: "Ramsey, Gordon" },
    { id: 3, displayName: "White, Betty" }];

        $scope.addSalesman = function (salesman) {
            if (!salesman.id) return;
            var result = $.grep($scope.addedSalesmen, function (e) { return e.id == salesman.id; });
            if (result.length === 0) {
                $scope.addedSalesmen.push(salesman);
            }
            $scope.salesmanEntry = { id: -1, displayName: "" };
        };

        $scope.removeSalesmen = function () {
            $scope.selectedSalesmen.forEach(function (salesman) {
                var index = $scope.addedSalesmen.indexOf(salesman);
                $scope.addedSalesmen.splice(index, 1);
            });
            $scope.selectedSalesmen = [];
        }
    }
]);

template:

<div ng-app="manageProductsModule">
    <div class="container" ng-controller="productDetailCtrl">
        <h3>Model Details</h3>
        <form class="form-horizontal" role="form" ng-if="!loadingProduct">
            <div class="form-group">
                <label for="addSalesmenInput" class="control-label col-md-2">Add</label>
                <div class="col-md-4">
                    <div class="input-group">
                        <input name="addSalesmenInput" 
                               class="form-control" 
                               ng-model="salesmanEntry" 
                               typeahead="salesman as salesman.displayName for salesman in allSalesmen | filter:$viewValue" />
                        <div class="input-group-btn">
                            <button class="btn" ng-click="addSalesman(salesmanEntry)" ng-disabled="!salesmanEntry">
                                <i class="glyphicon glyphicon-plus"></i>
                            </button>
                        </div>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <label for="salesmenInput" class="control-label col-md-2">Salesmen With Access</label>
                <div class="col-md-4">
                    <select name="salesmenInput" multiple="multiple" size="8" class="form-control" ng-model="selectedSalesmen" ng-options="salesman as salesman.displayName for salesman in addedSalesmen"></select>
                    <button class="btn" ng-click="removeSalesmen()" ng-disabled="!selectedSalesmen || selectedSalesmen.length === 0">
                        <i class="glyphicon glyphicon-minus"></i>
                    </button>
                </div>
            </div>
        </form>
    </div>
</div>
Ryan Langton
  • 6,294
  • 15
  • 53
  • 103
  • Could you include your template code as well please? – Mindstormy Jun 04 '14 at 15:48
  • added template code, the section for the typeahead and list box are towards the bottom of the html – Ryan Langton Jun 04 '14 at 15:51
  • If it is exactly the same code... what about the version of Angular and other plugins? – Patrick Ferreira Jun 04 '14 at 15:55
  • I copied the library CDN's from my Fiddle, they're using the exact same libraries and versions. – Ryan Langton Jun 04 '14 at 16:01
  • I've reduced my code dependancies to almost nothing to match the jsfiddle (see post). It's still exhibiting the same behavior, fiddle works fine, my code does not. – Ryan Langton Jun 04 '14 at 19:18
  • I've found my objects in the debugger, when I hit the functions and inspect the scope. I can find selectedSalesmen and salesmanEntry in the $$childHead. Why would this occur? It's like I'm getting the wrong $scope in my function. – Ryan Langton Jun 04 '14 at 19:38

1 Answers1

0

So here is what I had to do to get this to work. I am definitely not happy with what seems like a very hacky solution and would like to know why this is necessary. I had to go to $scope.$$childHead to access salesmanEntry and selectedSalesmen as they are apparently being stored on the wrong scope.

    $scope.addSalesman = function (salesman) {
        if (!salesman.id) return;
        var result = $.grep($scope.addedSalesmen, function (e) { return e.id == salesman.id; });
        if (result.length === 0) {
            $scope.addedSalesmen.push(salesman);
        }
        $scope.$$childHead.salesmanEntry = { id: -1, displayName: "" };
    };

    $scope.removeSalesmen = function () {
        $scope.$$childHead.selectedSalesmen.forEach(function (salesman) {
            var index = $scope.addedSalesmen.indexOf(salesman);
            $scope.addedSalesmen.splice(index, 1);
        });
        $scope.$$childHead.selectedSalesmen = [];
    }
Ryan Langton
  • 6,294
  • 15
  • 53
  • 103