What I want to do is to load separated templates and append a controller to each one:
an approach:
$http({
method: 'GET',
url: 'templates/myTemplate.html',
controller:'myCtrl'
})
function myCtrl($scope){
$scope.var1= "scoped variable";
}
myTemplate.html:
A Tag
{{var1}}
that is an aproach to this question:
Loading an AngularJS controller dynamically
It appears that your scenario would be a good place to apply ng-include. For example, given this markup:
<div ng-controller="MainCtrl">
<div ng-include="template"/>
</div>
and this code in MainCtrl:
function MainCtrl($scope) {
// some logic that would determine the template you want to load
$scope.template = 'templates/myTemplate.html';
}
and this code in templates/myTemplate.html:
<div ng-controller="TemplateCtrl">
<!-- Template Content -->
</div>
angular will automatically download templates/myTemplate.html and apply TemplateCtrl to the template. (Of course you'd also need to have TemplateCtrl defined.) When you want to switch templates, in MainCtrl you'll need to change the value of $scope.template to another template url; that template would specify an ng-controller attribute that indicates the appropriate controller for that template.
Related
[EDITED] My app has the following structure:
index.html
<body ng-app = "myApp" ng-controller ="mainController">
<ng-view></ng-view>
</body>
mainView.html (loaded into ng-view through routeProvider in app.js)
<div ng-include src="subview1">
<div ng-include src="subview2">
subview1 and subview2 are set within mainController (mainView's controller) as scope variables:
$scope.subview1= "templates/subview1.html";
$scope.subview2= "templates/subview2.html";
controller1 and controller2 are subview1 and subview2's controllers.
subview1.html (loaded in first div of mainView)
<div ng-controller="controller1">
<button ng-click="loadNewView()"></button>
</div>
controller1.js
.controller('controller1', function($scope){
$scope.loadNewView = function(){
$scope.$parent.subview1 = "templates/view3.html";
}
}
scope.loadNewView should load a different view (and relative controller) within the div with src="subview1" in mainView.html). Basically it's about refreshing the view itself by raplacing it with another view (and related controller).
I use $parent to update the view in subview1's parent view (i.e. mainView).
however nothing happens and if I try to use $scope.$apply() I get error (digest already in progress).
Any clue?
you can try something like this...
In your stateProvider or in your routeProvider if you using.
var mod = angular.module('example.states', ['ui.router']);
mod.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('exampleState', {
url: '/main',
templateUrl: 'mainView.html',
controller: mainController
});
}
]);
return mod;
So here you have associated your parent controller(let's say the mainController which will be the parent of all others) with its template mainView.html.
Then in your mainView.html,Load all the subview templates.
<div ng-repeat="template in templates">
<ng-include src="template.url"></ng-include>
</div>
templates is an array in your mainController which has the url or path of all your subtemplates.When you use ng-include inside the main template then all subTemplates will automaticlly become the child of the mainTemplate and its Controllers too.In a way it will inherit from the parent Controller.
So suppose if subView1.html is one of the template url you had given in ng-include.Then it will look like
<div ng-controller="subView1Controller">
//Here your code
</div>
And subview2 as
<div ng-controller="subView2Controller">
//Here your code
</div>
This way you will have multiple views on the same page with one url and different controllers with its associated templates and each will inherit from the parent controller which is mainController here.
There, might be better approach than this.
This is what i had used in my project,and its simple to keep your code simple manage.
Okay,so using routeProvider,you can use it like this
var app = angular.module("app",[]);
app.config(function($routeProvider){
$routeProvider
.when('/main',{
templateUrl:"mainView.html",
controller:mainController
})
});
app.controller("mainController",function($scope){
});
app.controller("subView1Controller",function($scope){
});
app.controller("subView1Controller",function($scope){
});
Then in your mainView.html,Load all the subview templates.
<ng-include src="yoursubtemplate1path"></ng-include>
<ng-include src="yoursubtemplate2path"></ng-include>
And then in yoursubtemplate1 use
<div ng-controller="subView1Controller">
//Here your code
</div>
Same for the other templates.
You can set the template src of the subtemplates from your mainController.
app.controller("mainController",function($scope){
$scope.templatesrc="/app/template1.html";
});
And then use it in your template,where you are using ng-include directive.
<ng-include src="templatesrc"></ng-include>
Its better to store template url's in an array and use ng-repeat directive like i had stated before,if you are loading more templates.
And if you want to show the div on some button click lets say in parent controller then use ng-if in the sub-view main and make it true on button click.
This answer is regarding your updated question.
The solution which you had used before,will load all temlplate and once in ng-include and its associated controller making the mainController as parent.
But if you want to load a different view with its newController then you can try something like this.
Just add one more route and call on your event click,but remember this newView's Controller will have no parent-child relation with the mainView's controller.
var app = angular.module("app",[]);
app.config(function($routeProvider){
$routeProvider
.when('/main',{
templateUrl:"mainView.html",
controller:mainController
})
.when('/anyName',{
templateUrl:"templates/view3.html",
controller:temp3Controller
})
});
And in your controller1.js
.controller('controller1', function($scope){
$scope.loadNewView = function(){
$location.path('/anyName');
}
}
Inject location service in controller1.
I finally found the solution.
The tricks is using
$scope.$parent.$parent.subview1 = "templates/view3.html";
instead of
$scope.$parent.subview1 = "templates/view3.html";
since, basically:
ng-include is the child of mainView
subview1 is the child of ng-include
I am new to angularjs, and I have an jquery background.
I want to compile json from the server into an element with an template.
What I now have for so far is:
The template:
<script type="text/ng-template" id="/tiles.html">
<div ng-repeat="tile in tiles">
{{tile.name}}<img ng-src="tile.src" />
</div>
</script>
The button for displaying the content:
<button ng-click="imageOptions.addFromList()">+ Add Image from list</button>
The function:
$scope.imageOptions.addFromList = function (){
$http
.get('/json/Tiles/get')
.success(function(data){
$scope.tiles = data;
console.log(data);
})
.error(function(data){
console.log("something did go wrong");
});
$(".prompt").html('<div ng-include src="/tiles.html"></div>');
};
The placeholder:
<div class="prompt"></div>
The placeholder will be used many times with also other content.
So I can not just type the html from the .html() argument. Like this:
<div class="prompt"><div ng-include src="/tiles.html"></div></div>
When I inspect the .prompt div it will stay uncompiled
The first thing you should do is remove jQuery library from your app while you get familiar with angular methodology.
There is no need to use html() method when all you need to do is include your template through a variety of different ways in your html source.
If the data isn't already available for ng-repeat it will simply fail quietly and do nothing. Then when the data is available it will respond automatically.
You could simply do:
<div class="prompt" ng-include src="/tiles.html"></div>
Or you could make a simple directive that will accomplish the same thing .
app.directive('prompt', function() {
return {
restrict: 'C',/* use for "class" */
templateUrl: '/tiles.html'
}
});
Simply change this
<div ng-include src="/tiles.html">
to this
<div ng-include src="'/tiles.html'">
While coding your single page application in angularjs, ideally there should not be any need for you to first get a reference to an element and then perform some action on it (You may think of this as the first step of switching from a jquery background to angularjs domain).
To achieve complete separation of model, view and controller you should just define your templates and controllers accordingly. These mappings and references should be managed by angularjs on its own.
As correctly mentioned above you should not be using .html() method of jquery. If you have included jquery in your document, it will be internally used by angularjs, but, including jquery should not be mandatory for using angularjs.
ng-repeat and ng-include also create a separate scope, so you may want to take care of those as well in future.
For your query, you may reference the template by including extra quotes in ng-include as:
<div class="prompt">
<div ng-include src="'tiles.html'"></div>
</div>
http://jsfiddle.net/PKKp8/
Consider the following:
<script type="text/ng-template" id="myTemplateName">
{{item.SomeProperty}}
<script>
<div ng-repeat="container in List">
<div ng-repeat="item in container.Items">
<!-- CASE 1 -->
<div ng-include="'myTemplateName'"></div>
</div>
<!-- CASE 2 -->
<div ng-include="'myTemplateName'" />
</div>
The code above works in case1, but not in case2: case 1 will work because the template uses item, which is made available by the ng-repeat statement outside of the template, case 2 doesn't work because there is no item, instead i want it to use container.SomeProperty.
Maybe i am misusing angular includes, but i wanted to use them like partials in ASP.Net MVC. There, you can define a partial and you are able to pass in a model.
Is there any way in angular that allows me to set what item means inside the template?
Problem solved using Matt's answer:
module.controller("ItemController", ['$scope', function ($scope) {
$scope.templateitem = ($scope.$parent.item) ? $scope.$parent.item : $scope.$parent.$parent.container.Item;
}]);
Still, it feels kind of dirty: the controller needs to know how it can be used. It would be better if i could pass this to the controller from the outside.
A better approach:
I didnt really like the solution above, because the controller needs to know how it will be used, so i used a directive:
app.directive("opportunity", function () {
return {
restrict: "E",
templateUrl: "opportunityTemplate",
scope: { templateitem: "=model" }
};
});
In view:
<script type="text/ng-template" id="opportunityTemplate">
{{templateitem.SomeProperty}}
</script>
<opportunity model="container.Item"></opportunity>
<opportunity model="somethingElse.Item"></opportunity>
Now all i need to find out is how i can pass the templatename into the directive, and i can make a re-usable "partial" directive (please tell me if i am reinventing the wheel here?)
What you need to use is ng-controller, or some routing system like ui-router that connects partials to controllers through route definitions.
For the first example, when you add your partial, also specify a controller which takes care of dealing with the model:
HTML:
<div ng-controller="MyCtrl" ng-include="'myTemplateName'" />
<!-- inside the template -->
<div>{{item.somekey}}</div>
Controller:
angular.module('myapp.ctrl', [])
.controller('MyCtrl', ['$scope', function($scope){
$scope.item = { somekey: 'somevalue' };
}]);
In the second example, use a routing system like ui-router. An example of that can be seen here, where certain partials are attached to controllers and specific urls:
https://github.com/angular-ui/ui-router/tree/gh-pages/sample
What I'd like to achieve is a reusable tabbed element that can load in a custom directive based on the current active tab. A directive within a directive.
I've built the tab wrapper element and have got the tabs to update $scope.activeTab, and inside this element I've hard-coded .
What I'd like to do is to have the tabs dictate which directive is inside, so it could be description-element, or image-element, or meta-element etc...
I could easily accomplish this by writing all the elements inside the tab wrapper when it loads and then use ng-hide to toggle them as the tabs are clicked, but I'd really like to be able to AJAX in the content and replace what is there when the tabs change.
Can anyone help?
You may be after ng-switch http://docs.angularjs.org/api/ng.directive:ngSwitch
It will remove from the DOM the elements that don't match the condition.
<div ng-switch on="item">
<div ng-switch-when="image"><image-directive /></div>
<div ng-switch-when="meta"><meta-directive /></div>
</div>
controllers.controller('appCtrl', function ($scope) {
$http({method: 'GET', url: '/someUrl'}).
success(function(data, status, headers, config) {
$scope.item = data.elementType;
}).
});
I've this routes.
// index.html
<div ng-controller="mainCtrl">
<a href='#/one'>One</a>
<a href='#/two'>Two</a>
</div>
<div ng-view></div>
And this is how I'm loading the partials into my ng-view.
// app.js
var App = angular.module('app', []);
App.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/one', {template: 'partials/one.html', controller: App.oneCtrl});
$routeProvider.when('/two', {template: 'partials/two.html', controller: App.twoCtrl});
}]);
When I click the links, it shows me the appropriate markup inside the ng-view. But when I try to include partials/two.html inside partials/one.html using ng-include, it shows it properly but creates a different scope so I'm not able to interact with it.
// partials/two.html - markup
<div ng-controller="twoCtrl">I'm a heading of Two</div>
// partials/one.html - markup
<div ng-controller="oneCtrl">I'm a heading of One</div>
<div ng-include src="'partials/two.html'"></div>
How do I resolve this problem? Or Is there any other way to achieve the same result?
You can write your own include directive that does not create a new scope. For example:
MyDirectives.directive('staticInclude', function($http, $templateCache, $compile) {
return function(scope, element, attrs) {
var templatePath = attrs.staticInclude;
$http.get(templatePath, { cache: $templateCache }).success(function(response) {
var contents = element.html(response).contents();
$compile(contents)(scope);
});
};
});
You can use this like:
<div static-include="my/file.html"></div>
The documentation for ngInclude states "This directive creates new scope." so this is by design.
Depending on the type of interaction you are looking for you may want to take a look at this post for one way to share data/functionality between the two controllers via a custom service.
So this isn't an answer to this question but i made it here looking for something similar and hopefully this will help others.
This directive will include a partial without creating a new scope. For an example you can create a form in the partial and control that form from the parent controller.
Here is a link to the Repo that i created for it.
good luck :-)
-James Harrington
You can actually do this without using a shared service. $scope.$emit(...) can dispatch events to the $rootScope, which can listen for them and rebroadcast to the child scopes.
Demo: http://jsfiddle.net/VxafF/
Reference:
http://www.youtube.com/watch?v=1OALSkJGsRw (see the first comment)