ngHide/ngShow using $rootScope in Single Page Application - angularjs

Reaching out to you all for help yet again for AngularJS. I'm building a SPA where my Layout (master) Page is divided in to three section left navigation bar, center content, right item list bar. My right item list should be hidden when I load my home page, but should be visible in the remaining screens. I've created a $rootScope variable in the homeController and setting the value to 'true' based on the location path and using that variable in the template to set the value to ngHide. When I navigate to a different page as I'm using SPA, my right and left bars won't be loaded again, only my center content do which is a new view. While loading the new view in the controller that is sending the data to the new view's template I'm resetting the $rootScope variable that I've created in homeController to 'false', but my right bar is still not visible. I could see that ng-hidden class is still on though the interpollation has updated the value to 'true'. Any suggestions would be highly appreciated.
markup from layout page:
<aside class="right_bar" ng-hide="{{$root.show}}">
<div class="my-list"><span class="f3">My Cart</span><div class=""><span class="list-count">0</span></div></div><div class="list-item"><ul></ul></div>
</aside>
homeController code:
function getHomeConfigsCtrl($http, $location, $rootScope) {
$rootScope.show = false;
var loc = $location.path();
if (loc === '/Home/Index' || loc ==='')
{
$rootScope.show = true;
}
}
Categories Controller code: This is where I'm resetting my $rootScope variable's value
function getAllCategoryDetails($routeParams,$rootScope) {
$rootScope.show = false;
}

Two things about angular you need to know to make your presented code works:
You don't need to interpolate values using {{}} in ng directives, instead use ng-hide="showCart".
Assuming all your controllers are within the same angular application,
all scopes within the same application inherits from the same root,
i.e whatever you define on the $rootScope will be available to all
child scopes. To access the $rootScope.x from within any view in the application all you have to do is: {{x}} or in your case you're using it inside a directive you can do something like this:
<aside class="right_bar" ng-hide="showCart">
This will look for your current scope, if it has a showCart then it'll use it, otherwise it'll fetch the $rootScope.showCart

Related

Retain Tab number in Navigation AngularJs

So I am relatively new to AngularJs and I am trying to figure out the best way for a tabController to remember what tab was previously clicked when switching to a new controller. So the situation would be I have 3 tabs. I click on tab 3 and then I click on something inside of it bringing me to a new controller and HTML template... What is the best way if I hit a "back" Button I created in that controller to remember exactly the state of it being the 3 tab.
I tried using $rootScope and then in each controller setting the tab number and setting the tabcontroller = $rootScope... but that was chaotic and too repetitive, and its not the right way.
This is not about $windoe.back(), this refers to coming up with a way that no matter where the navigation is the tab number is retained.
You can use a factory for this. In angular, a factory is a singleton, meaning only one instance of it exists for the whole project. Thus, by making something with it in one controller (and saving what you've did), you can access your changes in another controller.
angular.module('awesomeApp')
.factory('tabHistoryFactory', function () {
var tabHistory = {
setPrevTab: function(tab) { tabHistory.prevTab = tab; },
getPrevTab: function() { return tabHistory.prevTab; }
};
return tabHistory;
});
Then, in your first controller you'll have to inject this factory and before changing to another tab, just save the tab you're on using tabHistoryFactory.setPrevTab(tab). Then, in your second controller, you can access your previous tab by using tabHistoryFactory.getPrevTab(). Similarly, you can customize the behavior of your tab history by implementing other functions alongside those two.
Good luck!

How to display the value of other controllers in one view dynamically

I am working on an application were index page and inside that I am showing multiple views, In index nav bar I have to show notification count and User name which comes from 2 different controllers,
I am able to display the notification count and User name successfully, but the issue is the values are not changing dynamically.
We need to refresh the page for the new values.
What can I do in this situation can any one please guide me.
I'm guessing you're watching the value directly and not by some object wrapper. In this case javascript isn't actually updating the variable, but assigning a complete new one. Anything out of the function scope that updates the variable will never receive the new value.
The solution is simple; wrap the value in an object and share/inject that object.
angular.module('myApp')
.value('myPageState', {
notificationCount: 0
});
angular.module('myApp')
.controller('myController', function($scope, myPageState) {
$scope.myPageState = myPageState;
});
<div class="my-notification-thingy"> {{ myPageState.notificationCount }} </div>
You can achieve it by:
Maintain those values in rootScope so that you
will have the two way binding.
Making use of emit to notify the parent controller about value changes. This will work only if those two controllers are present in child elements.
In child controllers fire event on value update:
$scope.$emit('valueChanged', {value: val});
In parent controller receive event value:
$scope.$on('valueChanged', function(event, args) {
console.log(args.value);
});

Foundation error/fade flashes with ngAnimate before ngModel loads

I've got a directive, with a field in it. The field is being passed a $scope with the model in it.
The field is ng-required="true".
Because there is a split second where the data isn't loaded into the template, there is an unsightly flash of red error text around the field.
I've tried template caching, changing the class colour, but none of it happens at the right time. What we've done in the interim is remove ng-animate. This stops the delay and flash and fade. However, this is a set back as animations would be swell in other places.
From here I will ask the concrete question:
As ngAnimate is injected in the app.js, is there a way to disable injection at a per element/controller/directive level?
As far as I know, injection cascades when it is included in the global app.js.
What I've done is set a flag to signal when the content has finished loading, and I don't show any content until that's been set to true.
On your controller
$scope.finishedLoading = function() {
... whatever logic you need to figure out if all your data is loaded ...
return $scope.myData != null;
}
Then in some part of your template that wraps the fields you want initially hidden:
<div ng-hide="finishedLoading">Please wait...</div>
<div ng-show="finishedLoading">
.. your page content here ..
</div>

How to get the active status of nested Angular UI Bootstrap tabs

In my code I'm using a service (ngResource) to get data dynamically from the server API to create a series of nested tabs.
My code is loosely like this:
var AdminMenu = angular.module('AdminMenu', ['ngResource', 'ui.bootstrap', 'ngGrid']);
AdminMenu.factory('myServices', ['$resource', function($resource) {
return $resource('/api/categories?sort=createdAt asc');
}
and my controller
$scope.categories = myServices.categories.query();
On my template (jade) I have
tabset
if(categories)
tab(ng-repeat="category in categories", heading="{{category.name}}", active="category.active", disabled="category.disabled")
tabset
tab(ng-model="subCats", ng-repeat="subcat in subCats", heading="{{subcat.name}}", active="tab.active") {{subcat.content}}
And that works ok, however I need to get the status (active and heading) of the second and third(not created yet) generation tabs. I can get it from the first generation as Angular seems to automatically add bits to each object of the first generation like active:true, some methods, etc. The same doesn't seem to apply to the subsequent generations.
Interestingly, the tabs are not declared in my controller (like $scope.tabs = obj for instance), they are being added dynamically.
How can I access the status and heading (all details, really) of each subsequent generation of tabs?
I've tried assign the second and third generation in my controller like so: $scope.tabs2 = $scope.categories.subcategories but that didn't work. I suspect it was because the data is being collected dynamically, but I'm not sure. Since I can't assign the tabs in my controller, I can't simply console $scope.tabs2.active to find out which tab is active.
Any suggestions?

AngularJS - augmenting dynamic HTML content with user-generated content

I'm new to AngularJS and hoping someone can help me get my head round this please!
I'm developing a web e-reader that pulls in pages of HTML content dynamically. So far, I'm doing that with an $http AJAX call and binding it in with 'ng-bind-html-unsafe' (the HTML is our own, simply served from a directory on the same server. I have control over the HTML so I could do this differently if needs be). So each time the user presses previous/next, the controller simply fetches in the previous/next page of HTML and switches that in the model - that works great.
But next I need to augment this dynamic HTML with user additions, e.g. comments and highlights. They need to appear where the user adds them, e.g. a comment would most likely sit underneath a particular paragraph.
With JQuery I guess I would give each of the HTML elements its own ID and associate each bit of user-generated content with a particular ID. Then I could manipulate the DOM myself, for example adding each comment under its associated element.
What's the right approach with AngularJS, since the principle seems to be to avoid direct DOM manipulation altogether?
I could see how it could be done by defining the HTML content as separate elements in the model, having individual JavaScript objects for each paragraph, header, image, etc. But that would basically be defining DOM-like data in JavaScript - and that feels quite wrong and messy...
Use an "ng-include" and dynamically bind a src attribute from the controller. Adding dynamic, user generated content is as adding the binding variables to your html. Following is angular code that implements previous/next buttons that dynamically loads html templates and populates them with the user added comments. At the bottom is a link to a fully functional jsfiddle.
angular.module('app',[]).controller('controller', function($scope){
var change;
change = function(){
$scope.src = $scope.page + '.html';
};
$scope.page = 1;
$scope.items = [];
change();
$scope.submit = function(text){
$scope.items.push(text);
};
$scope.next = function () {
if($scope.page < 3){
$scope.page++;
change();
}
};
$scope.previous = function () {
if($scope.page > 1){
$scope.page--;
change();
}
};
});
http://jsfiddle.net/jwanga/rnL7c/

Resources