Let's say I am using a custom directive named my-form-data:
<my-form-data info='infoObj1' template="ssc.html"/>
<my-form-data info='infoObj2' template="college.html"/>
Inside directive definition, I want a different templateUrl based on the template attribute of the directive on the HTML page.
Is there any way to specify the controller class associated with ssc.html and college.html?
Use different directives. Its just a couple lines of code and they'll have their own template HTML. They can all share the same controller if desired or have their own. It doesn't make sense to try and use the same directive if you have different views and different controllers.
To answer your question directly, you can specify the controller in your directive HTML using ng-controller.
ssc.html
<div ng-controller='sscCtrl'>
...
</div>
college.html
<div ng-controller='collegeCtrl'>
...
</div>
Related
I've got a list of pop-ups/dialogs (enclosed in divs) that I want to place in a single HTML file and from there reference in different directives representing those pop-ups. As far as I know, AngularJS directive's templateUrl normally reference an HTML file. Is it possible to reference a single div within HTML for templateUrl? If it is, how to do it?
If your template fragments are small, you can reference them from within your JS by using the template: parameter instead of templateUrl:. However, in my projects, I reference all the template partials by templateUrl and use a grunt task to preload all the individual HTML files into one Javascript file that is then loaded by Angular into the template cache. You can read more about it here.
You can do the following:
Add the div's as a <script> and add the attributes type="text/ng-template" and id="", then when you set the templateUrl:, you pass the id from the script element.
Example:
HTML:
<script type="text/ng-template" id="template/awesomeDiv.html">
<div>
(...)
</div>
</script>
Directive:
templateUrl: 'template/awesomeDiv.html'
NOTE:
In order to use this, you need to have nested directives, so the parent directive includes your HTML with all divs, and the children uses the ng-template'd divs
I had the intention to use one template across several views having different controllers.
But now I realize that I cannot just write universal binding in templates because values will be put inside $scope.concreteControllerName.
Angular docs for ngInclude say that
This directive creates new scope.
I could use ng-init directive and pass controller instance to template's scope:
<ng-include src="..." ng-init="controller=concreteControllerName"/>
or even better
<ng-include src="..." ng-init="model=getModelForTemplate()"/>
and then write {{controller.boundvalue}} in template.
That is a working solution, I guess.
And here I'd like to know whether other better approaches exist and if not, should templates always be used with some notion of passed model to abstract away from parent scope?
Use John Papa's controllerAs View Syntax and controllerAs with vm. You specify different controllers in the ng-include directives but use the same src html template. The common vm variable name is used in the template.
index.html
<div ng-include ng-controller="controllerOne as vm" src="'same.html'"></div>
<div ng-include ng-controller="controllerTwo as vm" src="'same.html'"></div>
<div ng-include ng-controller="controllerThree as vm" src="'same.html'"></div>
controllerOne.js
function controllerOne() {
var vm = this;
vm.name = 'Controller One!';
sharedTemplate.html
<div>{{vm.name}}</div>
Here is a full working version: Full Working Code in Plunker
Question on loading second controller on click of button
Can I use controller inside another controller (like my example
below)
On click of "showMore" div, is it possible to call another
controller to load content in dialog ?
page1.jsp
<div ng-controller="FirstController">
<div ng-click="showMore()">Text 1</div>
<div ng-click="showMore()">Text 2</div>
</div>
<!-- my modal dialog -->
<script type="text/ng-template" id="SecondController.html">
<div ng-controller="SecondController" style="top:20px;left:300px;position:absolute;">
<div ng-repeat="content in Contents">{{content}}</div>
</div>
</script>
page1.js
var app = angular.module('MyApp',[]);
app.controller("FirstController", function($scope, $templateCache){
$scope.showMore = function(){
$templateCache("SecondController.html");
// what should be done here to open Second Controller
// and populate "Contents" div
}
});
Can I use controller inside another controller (like my example below)
Yes, the way you have set up your template will allow you to use a separate controller for the modal subsection. It might however be better to go about it in another way.
On click of "showMore" div, is it possible to call another controller to load content in dialog ?
Angular controllers rarely directly interact, so information is mostly passed through services or broadcasts depending on your need. In this case, you need to populate the Contents variable in either the parent scope (FirstController) or Secondcontroller.Contents. In the latter case, you might need to change the ng-repeat reference to SecondController.Contents.
I would suggest that the easiest way to go about the intended functionality as I understand your intent, is to use a modal library like f.e. the Angular UI: http://angular-ui.github.io/bootstrap/ or ngDialog https://github.com/likeastore/ngDialog . Unless you have a specific reason not to, both of these projects have good examples of using modal dialogs that you can adjust to your own needs in your controllers.
You don't need to "load" the controller explicitly. Angular loads an associated controller when ng-controller directive is $compiled, or when route is used.
For you cases, you can do:
In the FirstController controller, declare a boolean on the scope:
$scope.showMore = false;
In the view:
<div ng-controller="FirstController">
<div ng-click="showMore = true">Text 1</div>
<div ng-click="showMore = true">Text 2</div>
</div>
<div ng-if="showMore" ng-include="'SecondController.html'"/>
You could also use states angular-ui-router (as suggested by another answer), but I feel that states are better suited for well-defined app states, and not so much for dialogs, which you want in your question.
P.S.
Also, the way you named your template - i.e. "SecondController.html" - suggests that your are thinking of controllers and views as coupled. They should not be. The controller should not care about whether it has a view/html associated with, what it is, and whether that HTML is displayed or not. All the controller should care about is managing the ViewModel "state" of the small part of the app that it controls, and marshaling data between ViewModels and Models.
You can have nested controllers, but the markup content will not be loaded from a template unless you do ugly things like <ng-include src="{{ somevar }}" (dont do that)
To actually have real nested routes, you'd be better off using something like:
angular-ui-router: [https://github.com/angular-ui/ui-router]
angular route segment: [http://angular-route-segment.com/]
I am trying to make a transitive transclusion, or call it “directive inception”.
I made this example to illustrate what I am trying to do:
http://plnkr.co/edit/0hFFHknDps2krtK1D9ud?p=preview
The directive “first” wraps the directive “second” in its template and the two of them use transclusion.
What I want to do is to bind a value from a controller to the html that is a child of the “first” directive.
So I wanted my example to display:
<h1>Chained transclusions test</h1>
<div>
<h2>First directive</h2>
<div>
<h2>Second directive</h2>
<div>Controller hello</div>
</div>
</div>
Obviously that is not what I got.
I tried to analyze the scope with the developer tool and I was surprised by the result scope tree:
the result trees
I thought angularJS would create a new scope when using the transclude feature in a directive. And that this scope would be a non isolate sibling of my directive isolate scope. But I cannot see any sibling of my first directive scope (although it uses transclude). Plus, every children of my “first” directive has a scope isolated from the controller scope since the “first” directive scope is an isolated one.
I don’t understand the behavior here.
Is the transclude inclusion completely forbidden in angularJS ?
Is it possible to create a directive with transclusion, that wraps another directive that uses transclusion ?
It seems to me that this is the whole power behind web components, the fact that transclusion or any other special caracteristics should be seen as “implementation detail”, and the component should be able to use other directives that hide their own implementation details.
Without getting into the details of scope creation when using isolate scope with transclusion... it is possible to nest transclusions, but in your example, you need to make scope.controllerMsg available to the first directive's isolate scope:
JS:
app.directive('first', function(){
return {
...
scope: { controllerMsg: '=text'},
...
}
});
HTML:
<first text="controllerMsg">
{{controllerMsg}}
</first>
Demo
I've a two directives with transcluding html which calls isolated scope.
This Plnkr works fine while templates are inline, but if I change template to templateURL, it stops work.
Are there any issues with compiling?
Loading the template use URL, Angularjs creates an additional transcluded scope I guess.
Try to use $$prevSibling.$$prevSibling to access the functions.
Btw, it is really hacky to use $$prevSibling.
<div authorization>Sign in</div>
<div registration>Registration</div>