Angularjs rootscope not updating ngClass - angularjs

I'm pretty sure it's something stupid again. I'm learning angularjs so I don't get the full scope yet but I'm getting there. I tried everything and really searched for anything I could find but nothing seemed to work.
I'm trying to do a ng-class="..." in my layout file but the expression is set in my controller but somehow it's not rendered. It is rendered when I put it in my ng-view file. I get that he only renders part of the file but I want him to render the ng-class on ng-view as well. Is this possible or is it easier to just put in a div inside the partial html file.
Simple html file
<body>
<ng-view ng-class="{ 'splash': splash=='splash' }"></ng-view>
</body>
My controller
angular.module('xxx.splash')
.controller('IndexCtrl', function($scope, $rootScope, config) {
$rootScope.splash = 'splash';
$scope.login = function(e) {
alert('Soon. How soon? Very soon.');
}
});

When you define a variable in the root scope, you can't access it in the same way as you define it in the local scope. $rootScope variables can be accessible in the AngularJS templates using $root.<variableName>, so your HTML file should be changed to this:
<body>
<ng-view ng-class="{ 'splash': $root.splash=='splash' }"></ng-view>
</body>
You can see the diffrence of $scope and $rootScope in this demo

Related

Angularjs ng-class condition for window.location

i'm trying to unset/set a css class at a specific path url
I tried writing this code, but without any success
<div ng-class="window.location.toString().includes('ocs')? '' :'icon-home'"></div>
in chrome console i see this:
<div ng-class="window.location.toString().includes('ocs')? '' :'icon-home'" class="icon-home"></div>
I need to create a new angularjs module and scope for do this?
As you are clearing the class if location contains 'ocs', the correct approach should be this:
// in you angularjs controller:
$scope.containesOCS = window.location.toString().includes('ocs');
And in the html:
<div ng-class="{'icon-home': !containesOCS}"></div>
And if you haven't created an angular module or controller, please do so first. Without the
ng-app the angular attributes won't work.

ng-include and ngRoute: how to make them work together? (i.e. route to a view wihin a ng-include)

[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

AngularJS load tabbed content directive dynamicly

I have a tabbed navigtion in my webapp that looks like this
Now I want to Change the directive each time the user clicks on one of the Navigation points. My Idea was to init the page with the first template.
$scope.currentDirective = $compile('<div order-Sale></div>');
Then when the user clicks on a tab, I wanted to change and compile the content again with a new directive in it. But for some reason this is not working. How would you proceed in order to archive this dynamic content loading? I really want to only load the content on necessary need and not just to show or hide it. I think using directives is the right way to go for it, but I'm a but stuck at the implementation... Someone any pointer ? (I don't want to use any jQuery)
What I tried [Edit]:
The controller.js
app.controller('pageController',['$scope','$compile', function($scope, $compile){
var templates = ['<div first-template></div>','<div second-template></div>'];
$scope.currentTemplate = $compile(templates[0]);
$scope.changeTemplate = function(id) {
$scope.currentTemplate = $compile(templates[id]);
};
}]);
The HTML
<div ng-controller="pageController">
<li>
<a ng-click="changeTemplate('1')">Change Template</a>
</li>
{{currentTemplate}}
</div>
UPDATE
$compile returns a linking function not a value, you cannot just bind it to your template with interpolation.
You should use ngBindHtml instead of regular bindings ( ngBind & {{ }} ).
ngBindHtml does compiling, linking and watching all out-of-the-box.
With ng-bind-html-unsafe removed, how do I inject HTML?
Here is a plunker
app.controller('pageController',['$scope','$compile','$sce', function($scope, $compile, $sce){
var templates = ['<div>first-template</div>','<div>second-template</div>'];
$scope.currentTemplate = $sce.trustAsHtml(templates[0]);
$scope.changeTemplate = function(id) {
$scope.currentTemplate = $sce.trustAsHtml(templates[id]);
};
}]);
The markup:
<div ng-controller="pageController">
<button ng-click="changeTemplate('1')">Change Template</button>
<div ng-bind-html="currentTemplate"></div>
</div>
For more robust dynamic content loading you have two good alternatives:
ngRoute from angular team.
ui-router from angular-ui team.
If you want to change and compile the content again, well that's exactly what ng-view/ ui-view directives already do for you.
Why not just use a directive:
You probably need to load a different template (html partial) for each tab.
You probably need to change the url based on the tab (and vice versa)
You probably need to instantiate a different controller for each tab.
ngRoute and ui-router come with their own directives.
You can implement your own route module if you want but that's more than just a directive.

Render string templates via ng-include

I am trying to render a piece of html, available on a dynamic route, the route is fetched via a $http.get() call, it returns a piece of html,
Just to give an example I try to load this html partial:
<h1>{{ pagetitle }}</h1>
this is a simple page example
I made a small fiddle, to mock the problem, but for the simplicity i left the http call out, and just added the html in a string on the scope.
The controller is:
function Ctrl($scope) {
$scope.data = {
view: "<h1>whaaaaa</h1>"
};
}
The page html is this:
<div ng-app="">
<div ng-controller="Ctrl">
<div ng-include src="data.view"></div>
</div>
</div>
The problem is that it does not add the string into the html file (ng-include), but it makes a http call to a url made of that string aparently.
So Is it not possible to just enter a string into an include? if not, what is the proper way to make an http call to a dynamic url, and enter the returned url into the page.
You can play with it in JSFiddle.
You can add static hooks to the template cache, so let's say you have a service that gets the template:
myApp.service('myTemplateService', ['$http', '$templateCache', function ($templateCache) {
$http(/* ... */).then(function (result) {
$templateCache.put('my-dynamic-template', result);
});
/* ... */
}]);
Then, you can do:
<div include src=" 'my-dynamic-template' "></div>
NOTE reference name must be wrapped in single quotes, this always bytes me.... NOTE
Do note that you'll have to have assigned it to the template cache before angular tries to resolve the url.
EDIT:
If the dynamic URL logic is simple enough, you can also use a conditional in the ng-include, e.g.
<div ng-include="isTrue() && 'template1.html' || 'template2.html'"
You can't do that with ng-include; reference:
ngInclude|src – {string} – angular expression evaluating to URL. If
the source is a string constant, make sure you wrap it in quotes, e.g.
src="'myPartialTemplate.html'".
Use directly ng-bind-html-unsafe like this:
<div ng-bind-html-unsafe="data.view"></div>
Demo
Creates a binding that will innerHTML the result of evaluating the
expression into the current element. The innerHTML-ed content will not
be sanitized! You should use this directive only if ngBindHtml
directive is too restrictive and when you absolutely trust the source
of the content you are binding to.
You can use ng-bind-html-unsafe
If you do not trust the html which comes from your ajax request, you can also use ng-bind-html which needs the $sanitize service to work (DEMO).
<div ng-bind-html="data.view"></div>
To use that you need to include an extra js file .
angular.module('app', ['ngSanitize']);
And of course add the app to ng-app:
<div ng-app="app">
ng-include expects a URL to an external HTML fragment, not an HTML string.
You want ng-bind-html-unsafe:
Updated demo.

How to include one partial into other without creating a new scope?

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)

Resources