AngularJS child controller binding - javascript

I am including a view using the ngInclude directive. The included view has properties that binds values to $scope.model. This is a problem, since the parent scope is using $scope.model. What i need to do is to "reroute" the included views $scope.model to the parent scope's property $scope.include1.model. How can i do this "scope reroute" the way i want to?
Here is an example showing my problem
<div ng-controller="myCtrl">
<div ng-include="'input.html'"></div>
<div ng-include="'input.html'"></div>
</div>
<script type="text/ng-template" id="input.html">
<div ng-controller="childCtrl">
<input type="text" ng-model="model"/>
</div>
</script>
As you can see i have two includes to the same view, and both input text boxes will be bound to the same value. I want to bind them to different values in myCtrl
I can't make any changes to either my childCtrl or the included view.

You can try this
<div ng-include="'input.html'" ng-init='model=include1.model'></div>
<div ng-include="'input.html'" ng-init='model=include2.model'></div>

Related

Angular ng-controller conflicting with ng-app

I'm trying to use a custom control to get contenteditable elements in Angular as described in this example. However, I also need to use a controller which causes the contenteditable portion of the code to fail even if my controller is completely empty.
This Plunker shows the desired behavior, but does not include the controller.
<body ng-app="myApp">
<div>
<h1 contenteditable ng-model="test">123</h1>
<textarea ng-model="test"></textarea>
</div>
</body>
This Plunker shows the addition of the controller to the div on line 10 of the HTML file, however the desired behavior from the first Plunker is no longer there.
<body ng-app="myApp">
<div ng-controller="mainController">
<h1 contenteditable ng-model="test">123</h1>
<textarea ng-model="test"></textarea>
</div>
</body>
You have to explicitly register a controller with the app - global controller functions are not allowed by default:
.controller("mainController", function mainController($scope){
});
This is now the default option in Angular v1.3+
(of course, you have other issues with binding to untrusted HTML, but that's a different story)

How to use a controller outside of ngApp's scope

Due to the structure of an existing project I'm working on, I'm stuck with a template that looks like this:
<div ng-app="example">
<div ng-controller="MainCtrl" id="inner">
{{ inside }}
</div>
</div>
<div ng-controller="MainCtrl" id="outer">
{{ outside }}
</div>
#outer is supposed to be using the same controller as #inner, but as it's located outside of ngApp's scope, {{ outside }} will not be evaluated. Unfortunately I can't change the template structure, so I tried to compile #outer's content like this:
app.run(function($rootScope, $compile){
$rootScope.$apply($compile(document.getElementById('outer'))($rootScope));
});
This works, but the controller function will be executed twice, which is not desired. Is there a better way to achieve my goal?
Working example on Plunker
what you could do instead, is NOT define ng-app at all in the html, and instead bootstrap angular via javascript.
for example you can do angular.bootstrap(document, ['example']); where 'example' is the angular module for the app for example angular.module('example', [
'ngResource', 'ui.router', ....
]);
you probably defined that yourself already.
This way, you define the ng-app on the entire document scope.
That is normal, you're initializing twice the controller. You could simply create another div, wrapping all the divs you want and use alias. But this will still initialize twice, but each div will have different values, like, {{inside}} on first div will not have the same as the second one has.
<div ng-app="example">
<div>
<div ng-controller="MainCtrl as FirstCtrl" id="inner"> // alias FirstCtrl
{{ inside }}
</div>
</div>
<div ng-controller="MainCtrl as SecondCtrl" id="outer"> // alias SecondCtrl
{{ outside }}
</div>
</div>
But if you intend to use just once the same controller, as far as I'm concerned, you'll have to wrap all divs you want to use the same controller, in just one div, like:
<div ng-app="example" ng-controller="MainCtrl">
<div id="inner">
{{inside}}
</div>
<div id="outer">
{{outside}}
</div>
</div>
This will initialize just once.
Other way, could be attaching ng-app and ng-controller in your html/body tags.

why ng-bind doesn't show values from rootScope set by ng-click

I want to store a variable within $rootScope. When I have a structure like this it all works OK, the second div displays the value:
<html ng-app>
...
<body>
<button ng-click="$rootScope.pr = !$rootScope.pr"></button>
<div ng-class="{some:$rootScope.pr}">{{$rootScope.pr}}</div>
</body>
But when I have a structure like this:
<body>
<div class="root-scope-value-1">{{$rootScope.mobileMenuCollapsed}}</div>
<div class="content-wrapper" ng-controller="MainController">
<nav class="navbar navbar-custom navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<div class="root-scope-value-2">{{$rootScope.mobileMenuCollapsed}}</div>
<button ng-click="$rootScope.mobileMenuCollapsed = !$rootScope.mobileMenuCollapsed">
The div with class root-scope-value-2 shows the value from $rootScope.mobileMenuCollapsed, but the div with class root-scope-value-1 which is up the DOM doesn't. Why so?
You do not have to use $rootScope in the view, scope's are implicitly bound to the views (even in case of controller As syntax, the alias becomes a property on the $scope which has the value of the controller instance reference). All the scopes ($scope.$new()) except isolated scope($scope.$new(true)) are inherited ultimately from rootscope so you will have the properties available on the rootScope automatically available on the scope. So here your controller MainController's scope is inherited from the rootScope.
Plnkr
As a better practice always place properties on an object on the rootscope (As in the plunker) just so when you make any changes to the properties (properties of an object on the rootScope) from the child scope, the changes gets reflected on the parent as well, because both of them point to the same reference.

Angular directive with a ng-switch containing an input: can it be done cleanly?

In brief
I'm looking for a cleaner way to work around an issue that involves isolate scopes. I'm not sure there's a better workaround that what I have, but I hope so as I'm not too happy with it.
The demo
Demo on Plunkr
Contains both a directive that shows the problem, and another one with the dirty fix.
Change the values of the inputs and see it doesn't get propagated for one of them.
The story
I wrote a directive that contains a ng-switch. The code is:
angular.module('core')
.directive('otherSearchField', function() {
return {
templateUrl: 'otherSearchField.html',
restrict: 'E',
scope: {
field: '=',
placeholder: '#',
condition: '#searchWhen'
}
};
});
Its template is:
<section ng-switch="condition">
<div ng-switch-when="true">
<input type="text" ng-model="field" placeholder="{{placeholder}}">
<button ng-click="search()">Search</button>
</div>
<div ng-switch-default>
{{field}}
</div>
</section>
I could rewrite it as a ng-if, but what matters really is that in both cases, a new scope is created by ng-switch or ng-if.
I use the directive this way:
<div ng-controller="Ctrl">
<other-search-field field="query.city" placeholder="City" search-when="{{edition.city}}"></other-search-field>
</div>
The issue
As you notice, in the directive template, we have an input bound to "field". That one is bound to the calling template via the = notation in the directive definition.
However, because we're not using the object notation, entering something in the input modifies the field in the ng-switch's scope, but does not propagate out of it.
A (dirty) solution
My current solution is to use the object notation in the directive's template, which means I need to pass the containing object to the directive, and the name of the property I want to modify.
<section ng-switch="condition">
<div ng-switch-when="true">
<input type="text" ng-model="fieldParent[field]" placeholder="{{placeholder}}">
<button ng-click="search()">Search</button>
</div>
<div ng-switch-default>
{{fieldParent[field]}}
</div>
</section>
Usage:
<my-search-field field-parent="query" field="customer" placeholder="Customer" search-when="{{edition.customer}}"></my-search-field>
This works: I'm using the object notation so the changes on the input propagate all the way up (see on the Plunkr linked above).
So ?
Hmm, I'm not too happy to pass an entire object when only one of its properties is needed though. Is there a better way ?
NB
Note I could also, in this case, use multiple ng-show as they don't create their own scope. But I'm interested in the more general issue shown here, not in this specific case.
Thanks for reading all the way. Kudos to you !
In your otherSearchField.html template, you can access the $parent $scope's field property, thereby accessing the isolate scope that your directive <other-search-field> is using.
DEMO
<section ng-switch="condition">
<div ng-switch-when="true">
<input type="text" ng-model="$parent.field" placeholder="{{placeholder}}">
<button ng-click="search()">Search</button>
<div>value in the template, in "switch": {{$parent.field}}</div>
</div>
<div ng-switch-default>
{{field}}
</div>
</section>
<div>
value in the template, out of "switch": {{field}}
</div>

AngularJS - ng-include ng-controller and scope not binding

I have the following main view
<div ng-include="'otions.html'"></div>
and options.html has the following
<div ng-controller="OptionsController">Options</div>
<input type="text" ng-model="keyword" value="{{keyword}}" />
<button ng-click="search()">Search</button>
But "keyword" is not binding to the scope in OptionsController.
app.controller('OptionsController',
['$scope', function($scope) {
$scope.keyword = "all";
$scope.search = function() {
console.log("hello")
};
}]);
when I click on the button, I don't see hello and the keyword all doesn't appear in the input text.
I tried moving the ng-controller part as follows
<div ng-controller="OptionsController" ng-include="'otions.html'"></div>
And things work as expected.
I read through the answers in AngularJS - losing scope when using ng-include - and I think my problem is related, but just need some more explanation to undertstand what's going on.
You should write options.html like this:
<div ng-controller="OptionsController">Options
<input type="text" ng-model="keyword" value="{{keyword}}" />
<button ng-click="search()">Search</button>
</div>
OptionsController should be put in the outer html element.
i have face same problem,
Under main tag it will be work fine but, When bind some data to nav.html it not work.
find this link
AngularJS - losing scope when using ng-include
inside include its work child scope.
better option to create custom directive its easy solution

Categories

Resources