How to Specify Model to a Nginclude Directive in Angularjs

How to specify model to a ngInclude directive in AngularJS?

NOTE: this is not my original answer but this is how I'd do this after using angular for a bit.

I would create a directive with the html template as the markup passing in the dynamic data to the directive as seen in this fiddle.

Steps/notes for this example:

  1. Define a directive with markup in the templateUrl and attribute(s) used to pass data into the directive (named type in this example).
  2. Use the directive data in the template (named type in this example).
  3. When using the directive in the markup make sure you pass in the data from the controller scope to the directive (<address-form type="billing"></address-form> (where billing is accessing an object on the controller scope).
  4. Note that when defining a directive the name is camel cased but when used in the markup it is lower case dash delimited (ie it's named addressForm in the js but address-form in the html). More info on this can be found in the angular docs here.

Here is the js:

var myApp = angular.module('myApp',[]);

angular.module('myApp').directive('addressForm', function() {
return {
restrict: 'E',
templateUrl: 'partials/addressform.html', // markup for template
scope: {
type: '=' // allows data to be passed into directive from controller scope
}
};
});

angular.module('myApp').controller('MyCtrl', function($scope) {
// sample objects in the controller scope that gets passed to the directive
$scope.billing = { type: 'billing type', value: 'abc' };
$scope.delivery = { type: 'delivery type', value: 'def' };
});

With markup:

<div ng-controller="MyCtrl">
<address-form type="billing"></address-form>
<address-form type="delivery"></address-form>
</div>

ORIGINAL ANSWER (which is completely different than using a directive BTW).

Note: The fiddle from my original answer below doesn't appear to work anymore due to an error (but keeping it here in case it is still useful)

There was a discussion about this on the Google Group you can see it here.

It looks like this functionality is not supported out of the box but you can use Brice's patch as described in this post.

Here is the sample code from his jsfiddle:

<script id="partials/addressform.html" type="text/ng-template">
partial of type {{type}}<br>
</script>

<div ng-controller="MyCtrl">
<ng-include src="'partials/addressform.html'" onInclude="type='billing'"></ng-include>
<ng-include src="'partials/addressform.html'" onLoad="type='delivery'"></ng-include>
</div>

How to get different ng-model values in ng-include of the same HTML file

If you are using AngularJS v1.5+, you can use component instead of ng-include. This is an example of a component you could create

Component JS

angular
.module('app')
.component('myDetailsComponent', {
bindings: {
data: '<'
},
controller: function () {
// do whatever you need with your input here
},
templateUrl: 'my-details.component.html'
});

Component Template

<input type="text" ng-model="$ctrl.data.Name">

View

<div>
<p>Journalist's Details:</p>
<my-details-component data="companion"></my-details-component>
</div>

Edit

If you are using an older version of AngularJS, you can replicate the same functionality with a directive. For example:

Directive JS

angular
.module('myDetailsDirective')
.directive('myDetailsDirective', myDetailsDirective);

function myDetailsDirective() {

return {
restrict: 'E',
scope: {
data: '='
},
templateUrl: 'my-details.directive.html',
link: function () {
// do whatever you need with your input here
}
};

}

Directive Template

<input type="text" ng-model="data.Name">

View

The usage of the directive is exactly the same as in the case of the component:

<div>
<p>Journalist's Details:</p>
<my-details-directive data="companion"></my-details-directive>
</div>

AngularJS dynamic template with ng-include and separate template directives

What we ended up doing is this:

we have one directive:

app.directive("searchResultsContainer", function() {
restrict: "E",
templateUrl: "search-results-container.html",
controller: function($scope) {
$scope.templates = [
{ viewmode: "list", url: "search-results-list-view.html" },
{ viewmode: "grid", url: "search-results-grid-view.html" },
{ viewmode: "table", url: "search-results-table-view.html" }
]
},
link: function(scope) {
scope.toggleView = function() {
scope.templates.push(scope.templates.shift());
}
}
}

This directive is instantiated by using an ng-include directive:

<search-results-container ng-include="views/result-list.html"></search-results-container>

The used result-list.html file has this passage:

<div ng-switch on="templates[0].viewmode">
<search-results-list-view ng-switch-default></gs-search-results-list-view>
<search-results-grid-view ng-switch-when="grid"></gs-search-results-grid-view>
<search-results-table-view ng-switch-when="table"></gs-search-results-table-view>
</div>

And it has a button to toggle between views, using a simple ng-click directive:

<button ng-click="toggleViewMode()">Toggle View</button>

This button triggers the searchResultsContainer's toggleView method, described in the directive above, moving the elements of the templates array around:

scope.toggleView = function() {
scope.templates.push(scope.templates.shift());
}

The ng-switch directive listens for changes in the "viewmode" property of the first element of the templates array:

ng-switch on="templates[0].viewmode" 

Such a change happens when clicking the button, thus changing the first element in the array entirely, which naturally also results in a change of the "viewmode" property, monitored by ng-switch.

The nested ng-switch-default and ng-switch-when directives react to the change and display the according element, which has the appropriate value set in "ng-switch-when".

The three children of the ng-switch each use a separate directive, here is one of them:

app.directive("searchResultsListView", function() {
return {
restrict: "E",
require: "^searchResultsContainer",
template: "<div ng-include=\"'views/list-view.html'\"></div>",
controller: function($scope) {
/* $scope stuff goes here */
},
link: function(scope, element, attrs, searchResultsCtrl) {
/* link stuff goes here */
}
}
});

Note the very important escaped quotation marks, followed by high-commas in the template's ng-include directive, as required by the ng-include directive (more info on ng-include).

Directives inside ng-include

Here is a working plunker: http://plnkr.co/edit/ilVbkHVTQWBHAs5249BT?p=preview

You got bitten by using a primitive value on the scope.

  • When you put fblogin outside of ngInclude it's on the same scope of the controller.
  • ngInclude always creates a new child scope so any directive inside it is on a child scope.

From Understanding Scopes wiki:

Scope inheritance is normally straightforward, and you often don't even need to know it is happening... until you try 2-way data binding (i.e., form elements, ng-model) to a primitive (e.g., number, string, boolean) defined on the parent scope from inside the child scope.

It doesn't work the way most people expect it should work. What happens is that the child scope gets its own property that hides/shadows the parent property of the same name. This is not something AngularJS is doing – this is how JavaScript prototypal inheritance works.

New AngularJS developers often do not realize that ng-repeat, ng-switch, ng-view and ng-include all create new child scopes, so the problem often shows up when these directives are involved.

This issue with primitives can be easily avoided by following the "best practice" of always have a '.' in your ng-models.

What happens in your case is that scope.saveTemplate = '/set/continue'; just create a variable on the child scope which shadows scope.saveTemplate of the parent scope (controller).

angularjs - custom directive in ng-include not working

I've changed your code a little bit so the boolean value will reside inside an object, and now you just have to watch that instead:

Controller changes:

mymodal.controller('MainCtrl', function ($scope) {
$scope.modalObj = { showModal : false };
$scope.toggleModal = function(){
$scope.modalObj.showModal = !$scope.modalObj.showModal;
};
});

Directive (main) change:

scope.$watch(function () { return scope.modalObj.showModal; }, function(value){
if(value == true)
$(element).modal('show');
else
$(element).modal('hide');
});

And also of course the lines will now refer to scope.modalObj.showModal instead of using the parent/attr keywords, in general you should try to avoid those.

Fiddle

Different ng-include's on the same page: how to send different variables to each?

The expression passed to onload evaluates every time a new partial is loaded. In this case you are changing the values of var twice so by the time both partials are loaded the current value will be B

You want to pass different data to each partial/template (with the underlying html file being the same). To achieve this, as Tiago mentions, you could do it with different controllers. For example, consider the following

<body ng-controller='MainCtrl'>    
<div ng-include src='"toBeIncluded.html"' ng-controller='ctrlA' onload="hi()"></div>
<div ng-include src='"toBeIncluded.html"' ng-controller='ctrlB' onload="hi()"></div>
</body>

Here, we have two partials, each with its own scope managed from their own controller (ctrlA and ctrlB), both children scopes of MainCtrl. The function hi() belongs to the scope of MainCtrl and will be run twice.

If we have the following controllers

app.controller('MainCtrl', function($scope) {
$scope.msg = "Hello from main controller";
$scope.hi= function(){console.log('hi');};
});

app.controller('ctrlA', function($scope) {
$scope.v = "Hello from controller A";
});

app.controller('ctrlB', function($scope) {
$scope.v = "Hello from controller B";
});

And the contents of toBeIncluded.html are

<p>value of msg = {{msg}}</p>
<p>value of v = {{v}} </p>

The resulting html would be something along the following lines

<p>value of msg = Hello from main controller</p>
<p>value of v = Hello from main controller A </p>

and

<p>value of msg = Hello from main controller</p>
<p>value of v = Hello from controller B </p>

Example here: http://plnkr.co/edit/xeloFM?p=preview

AngularJS ng-model does not work with ng-include

When you use ng-include, Angular creates a new scope, causing your variable to be overwritten to the new scope, instead of the one you wanted. As the new scope is an instance of the original scope (the one you want), you can create an object on CustomRowsCtrl; the objects are copied to the new scope as a reference, enabling you to share the same object in between child and parent scope.

Obs.: You can also use $parent, as suggested on the link below, but using pointers is a lot cleaner and if you use multiple nesting, you won't need to use $parent.$parent and so on.

Example:

On the controller:

$scope.selection = {} 

On the HTML:

ng-model="selection.numLines"

More about ng-include scope:
AngularJS - losing scope when using ng-include

ng-include with ng-click raise submit - how to avoid it?

use type="submit" with the submit button, and input instead of button.



Related Topics



Leave a reply



Submit