2

In an attempt to clean up my partials I recently moved some of my global menus into seperate templates which I now include in the views which need them. As the menu (including a search bar) is global I have created a service which keeps track of the state of the menu and so on.

Problem is something funny happened after I started including.

HTML (Jade) of the View

div(ng-controller='HeroUnitCtrl', ng-include src='heroTemplate')
div(ng-controller='MainSearchBarCtrl', ng-include src='searchBarTemplate')

div.row-fluid
    div.span12
        table.table.table-striped.table-bordered
            tr
                th
                    a(ng-click='setOrder("id")') ID#
                th
                    a(ng-click='setOrder("client.name")') Kunde
                th
                    a(ng-click='setOrder("technician.name")') Tekniker
                th
                    a(ng-click='setOrder("createdAt")') Opprettet
                th
                    a(ng-click='setOrder("statusString")') Status

            tr(ng-repeat='record in records | orderBy:orderProp | filter:searchBar')
                td
                    a(ng-href='#/records/show/{{record.id}}') {{record.id}}
                td {{record.client.name}}
                td {{record.technician.name}}
                td {{record.createdAt}}
                td {{record.statusString}}

HTML (Jade) searchBarTemplate

input#searchField.input-xxlarge(type='text', placeholder='placeholder', ng-change='searchBarUpdated()', ng-model='searchBar')

Now to the bit I really don't understand,

MainSearchBarCtrl

function MainSearchBarCtrl(MainSearchBarService, $scope, $location) {
    $scope.searchBarTemplate = 'partials/main-searchbar';
    $scope.searchBar = 'Hello World!';

    $scope.searchBarUpdated = function() {
        console.log('Search bar update: ' + $scope.searchBar);
        MainSearchBarService.searchBarUpdated($scope.searchBar);
    }   
}

Initially the value of searchBar is as expected "Hello World". However, if I append any text it still only prints "Hello World". Or, if I replace the text it prints undefined. So it seems the binding is broken, but I don't really see why this is happening. Worth mentioning is that this wasn't case before I moved my search bar into a separate template.

Any help is greatly appreciated.

Index
  • 2,351
  • 3
  • 33
  • 50
  • create a demo that replicates problem – charlietfl Mar 29 '13 at 15:24
  • Alright, I'll get a fiddle up. If you look at the top of the view it includes searchBarTemplate. – Index Mar 29 '13 at 15:24
  • I modified comment about scope... but hard to help without seeing a live version – charlietfl Mar 29 '13 at 15:25
  • Heh, okay. Here is the live version running on Heroku, http://katana-kvds.herokuapp.com/#/ – Index Mar 29 '13 at 15:28
  • 1
    ng-include creates a new child scope. So in your searchBarTemplate, using `ng-model="searchBar"` results in a new `searchBar` property being created on the child scope, which hides/shadows the parent `searchBar` property of the same name. Try using `$scope.obj = {searchBar: 'Hello World!}` in your controller, and `ng-model="obj.searchBar"` in your template. – Mark Rajcok Mar 29 '13 at 15:34
  • 1
    @MarkRajcok nailed problem, in future easier to put demos in **[Plunker](http://plnkr.co/edit/b:angularjs@1.1.x+starter-angularjs?p=preview)** so they can be edited and much easier to review code. Allows for really simple creation of external files for partials and different js files etc – charlietfl Mar 29 '13 at 15:39
  • Thanks for your replies. I wasn't aware of Plunker, so thanks for the heads up. – Index Mar 29 '13 at 17:09

2 Answers2

9

As discussed in the comments above, ng-include creates a new child scope. So in your searchBarTemplate, using ng-model="searchBar" results in a new searchBar property being created on the child scope, which hides/shadows the parent searchBar property of the same name.

In the controller, define an object:

$scope.obj = {searchBar: 'Hello World!};

And then use

ng-model="obj.searchBar" 

in your template. When objects are used (instead of primitives), the child scope does not create a new property. Rather, due to the way JavaScript prototypal inheritance works, the child scope will find the property on the parent scope.

See also https://stackoverflow.com/a/14146317/215945 which has a picture showing the child and parent scopes and how the child property hides/shadows the parent property if a primitive is used.

Note that using $parent is another option, but it is not "best practice".

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • Just a quick follow-up. Is it possible to access the child scope from the parent scope? I'm guessing not due to the inheritance, but. – Index Mar 29 '13 at 17:14
  • 1
    No... well yes, but you'd have to use Angular private $$ variables like ``$$childHead`` and such. I would not recommend doing that (ever). – Mark Rajcok Mar 29 '13 at 17:31
  • Does this look the same with the controllerAs syntax? – RJB Nov 03 '15 at 17:09
0

Try using $parent instead of $scope in your included template

alefalezza
  • 46
  • 4
  • 2
    That's a bad idea I think. Move your code into a partial view, or inside a directive, or both, and your code isn't working anymore. And to make it work you'll have to use $parent.$parent.... – Mat Jul 31 '15 at 10:44
  • https://github.com/angular/angular.js/wiki/Understanding-Scopes#ng-include – duchuy Aug 31 '16 at 09:33