By clicking the link i change view, this re-instantiating my controller. This is why the activeMenu is empty. If icreate a service and store the currently active menu in there, it won't be empty.How can i create service to do that? This is my first time that i need to create service?This is my plnkr... http://plnkr.co/edit/gJko3umteXXEye7o9StR?p=preview
Problem is when user click on menu from layout then this re-instantiating my controller
Layout:
<li class="dropdown">
<ul class="submenu">
<li>#Translate("MY_ACCOUNT")</li>
<li ng-click="GetLoader();">#Translate("SETTINGS")</li>
<li ng-click="GetLoader();">#Translate("TICKET_HISTORY")</li>
<li ng-click="GetLoader();">#Translate("TRANSACTIONS")</li>
<li ng-click="GetLoader();">#Translate("BONUS_ACCOUNT")</li>
<li>#Translate("ODDS_REPRENSETATION")</li>
<li>#Translate("HELP")</li>
<li>#Translate("LOGOUT")</li>
</ul> </li>
You can do it like this:
app.service('navigation', function () {
this.activeLink = '';
});
app.controller('MainCtrl', function($scope, navigation) {
$scope.activeMenu = 'Home';
$scope.activeLink = navigation.activeLink;
$scope.changeActiveLink = function(link) {
$scope.activeLink = link;
this.activeLink = link;
}
});
The service is a singleton, it's intatiaded once per you application load, so it will keep the assigned value between diffent states of your app.
You can make it a bit smarter if you won't store a simple string value but an object - this way we'll be able to keep the reference to the service's value rather than the value itself and we won't need to set both $scope.activeLink = link; and this.activeLink = link; explicitly:
app.service('navigation', function () {
this.active = {
link: '',
menu: 'Home'
};
});
app.controller('MainCtrl', function($scope, navigation) {
$scope.activenav = navigation.active;
$scope.changeActiveLink = function(link) {
navigation.active.link = link;
}
});
(just remember to make necessary changes in your html code in that second case)
Related
I'm trying to open a link using ng-href and as soon as I click on it, I need it to open an email address and populate its To, Subject and it's Body field. Can this be made possible?
I tried this,
<a ng-click=”sendMail($event)” href=”gmail.com” />
$scope.sendMail = function($event)
{
if($scope.showMailLink == true )
{
$event.preventDefault();
window.location = $event.target.href;
$window.open("mailto:veron#gmail.com?subject=hello&body=fggf_self");
}
};
This is what I've tried and it isn't actually right. Is this a valid approach?
You should use location.href:
location.href = "mailto:veron#gmail.com?subject=hello&body=fggf"
or target the current window:
$window.open("mailto:veron#gmail.com?subject=hello&body=fggf", '_self');
- Example -
View
<div ng-controller="MyCtrl">
<button ng-click="mailWithLocation()">
Mail via location.href
</button>
<button ng-click="mailWithWindowOpen()">
Mail via $window.open()
</button>
</div>
AngularJS Application
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function ($scope, $window) {
$scope.mailWithLocation = function () {
location.href = "mailto:veron#gmail.com?subject=hello&body=fggf"
}
$scope.mailWithWindowOpen = function () {
$window.open("mailto:veron#gmail.com?subject=hello&body=fggf", '_self');
}
});
I am displaying a list of host in the table under "hostController" controller. ClusterController is parent of hostController. Host is a tab inside Cluster view. Call for getting host should be done only when the cluster list is available(which is called when the dropdown on cluster view is clicked). So even if we have selected host tab, the host list call should not be fired and hence the host list should not be displayed(as cluster list is not available). But if we have selected host tab, and then we clicked the dropdown of cluster view to get the cluster list, the host list should be displayed. But its not happening so. The host list gets updated but the same changes is not displayed in the UI.
The dropdown in Cluster view which will call getClusterList() and will update the showNavContent poperty. The host list should be displayed only when showNavContent property is true. I am compiling the hostController again inside the clusterController, so the function getHostList is called and updated the hostVm.hostList property but on the UI it is not reflected.
//ClusterController
function clusterController($scope, $controller, $rootScope) {
var vm = this,
hostVm;
$rootScope.showNavContent = false;
function getClusterList() {
clusterStore.getClusterList().then(function(data) {
$rootScope.showNavContent = true;
hostVm = $controller("hostController as hostVm", { $scope: $scope});
});
};
//HostController
app.controller("hostController", hostController);
function hostController($scope, $rootScope, $state, $stateParams, hostStore, tabManager) {
var vm = this;
vm.getHostList = getHostList;
vm.activeTab = tabManager.getActiveTab();
vm.hostList = [];
init();
function getHostList() {
hostStore.getHostList().then(function(data) {
vm.hostList = data.data;
console.log(vm.hostList);
});
}
function init() {
if($rootScope.showNavContent === true) {
vm.getHostList();
}
}
}
//host.html
<div class="flex-table">
<div class="ft-row" ng-repeat="host in hostVm.hostList">
<div class="ft-column">
<div class="host-name">{{host.name}}</div>
<div>{{host.ip}}</div>
</div>
</div>
</div>
I have a Poller that I have setup that has 2 files which are being queried. When new data has been found I am trying to set the color of my text background in the view but its just not happening.
If someone can solve this issue that would be great I am also welcome to suggestions to improving the structure of the code.
Service:
function Poller($http, $timeout) {
var projectcache = { response: [], calls: 0 };
var msgcache = { response: [], calls: 0 };
var newdata = false;
var msgdata = false;
var msgcolor = {};
var projectcolor = {};
var poller = function () {
$timeout(poller, 10000);
console.log("Begin Poller!");
$http.get('http://localhost/app/controllers/php/getProjects.php')
.then(function(r) {
if (r.data.projects.length > projectcache.response.length) {
newdata = true;
projectcolor = 'green';
} else {
newdata = false;
projectcolor = 'green';
};
angular.copy(r.data.projects, projectcache.response);
console.log("New Data Found: " + newdata);
});
$http.get('http://localhost/app/controllers/php/getMessages.php')
.then(function(m) {
if (m.data.messages.length > msgcache.response.length) {
msgdata = true;
msgcolor = 'green';
} else {
msgdata = false;
msgcolor = 'green';
};
angular.copy(m.data.messages, msgcache.response);
console.log("New Msg Found: " + msgdata);
});
};
poller();
return {
projects: projectcache.response,
messages: msgcache.response,
newdata: newdata,
msgdata: msgdata,
msgcolor: msgcolor,
projectcolor: projectcolor
};
};
View:
<li ng-class="{active: selectTab=='inbox'}" style="background-color:{{msgcolor}};" ng-click="selectTab='inbox'">Inbox</li>
<li ng-class="{active: selectTab=='projects'}" style="background-color:{{projectcolor}};" ng-click="selectTab='projects'">Projects</li>
Controller:
app.controller("taskbarController", ['$scope', 'authData', '$location', 'projectsModal', 'sendMessageModal', 'Poller',
function ($scope, authData, $location, projectsModal, sendMessageModal, Poller) {
$scope.msgcolor = Poller.msgcolor;
$scope.projectcolor = Poller.projectcolor;
}]);
My first thought is to use ng-class for this. I see you already have ng-class handling the display of your 'active' class.
If you'd like to try this approach out, I would:
1. Create css clases for each state/color you want to change to. (Can do this in external css file or between tags you create at the beginning of your page.
.successBackground {
background-color:green;
}
.errorBackground {
background-color:red;
}
Modify your ng-class attributes. Here I am assuming that success means that msgdata=true and error means that msgdata=false
Current html:
<li ng-class="{active: selectTab=='inbox'}" style="background-color:{{msgcolor}};" ng-click="selectTab='inbox'">Inbox</li>
<li ng-class="{active: selectTab=='projects'}" style="background-color:{{projectcolor}};" ng-click="selectTab='projects'">Projects</li>
Updated html:
<li ng-class="{active: selectTab=='inbox', successBackground:msgdata===true, errorBackground:msgdata===false}" ng-click="selectTab='inbox'">Inbox</li>
<li ng-class="{active: selectTab=='projects',successBackground:msgdata===true, errorBackground:msgdata===false}" ng-click="selectTab='projects'">Projects</li>
Now when your msgdata is updated, the successBackground and errorBackground are automatically updated based on the latest msgdata value.
Hope this helps!
#Elevant, the comment option didn't allow me to format my code snippets, so I am replying to your latest comment in this answer post.
I'm not sure if the watcher can listen to just the Poller object or if it'll need to listen to each attribute separately (msgColor, projectColor). In my code snippet here, I'll assume we cannot and we'll need to listen to each individually.
Current code:
$scope.msgcolor = Poller.msgcolor;
$scope.projectcolor = Poller.projectcolor;
Updated with watchers:
$scope.$watch('Poller.msgcolor', function(newValue,oldValue) {
$scope.msgcolor = Poller.msgcolor;
});
$scope.$watch('Poller.projectcolor', function(newValue,oldValue) {
$scope.projectcolor = Poller.projectcolor;
);
Though if you still wanted to look into the option to move $timeout, I would make the following changes (not sure if this matches what you had tried).
In the Poller service definition remove $timeout. Updated snippet:
function Poller($http)
Still in Poller, remove this line:
$timeout(poller, 10000);
In the Controller add $timeout - updated snippet:
app.controller("taskbarController", ['$scope', 'authData', '$location', 'projectsModal', 'sendMessageModal', 'Poller','$timeout'
function ($scope, authData, $location, projectsModal, sendMessageModal, Poller,$timeout)
Then in the controller, you would add:
$timeout(function(Poller) {
Poller.poller();
$scope.msgcolor = Poller.msgcolor;
$scope.projectcolor = Poller.projectcolor;
}, 10000);
I hope this helps, I haven't had a chance to test the code, so you may have to tinker around with it a bit. Let me know how it goes!
I am currently developing a new project that uses AngularJS and Twitter Bootstrap 3.0 for styling.
The project also uses ASP.NET MVC WebAPI to provide a RESTful API with role based security as well as generating bearer and refresh tokens using Owin and OAuth.
One of the key aspects of the project is that it must be able to refresh the navbar menu by adding and/or removing menu options depending on the roles/permissions assigned to individual users. If a user is currently logged into the application and a system administrator decides to add or removed roles for the logged in user I would like AngularJS to automatically reload the navbar, which will magically show or hide options based on the roles the user has.
I do not know very much about AngularJS at this point and would like to know if this is possible? I have heard something called $scope.apply() and that it could be used for this, but as an inexperienced AngularJS user I am not sure how this could be used.
This is a portion of my view that displays the menu bar, and as you can see I am using functions to show/hide menu options. I'd like these functions to be re-evaluated again if their values change once a new refresh token has been generated by a WebAPI call.
<li data-ng-if="isAuthenticated()" class="dropdown">
Invoice <b class="caret"></b>
<ul class="dropdown-menu">
<li><a data-ng-if="isUserInInvoiceRole()" data-ui-sref="addInvoice">Add Invoice</a></li>
<li data-ng-if="isUserInInvoiceRole()" class="divider"></li>
<li><a data-ng-if="isUserInCreditNoteRole()" data-ui-sref="addCreditNote">Issue Credit Note</a></li>
<li data-ng-if="isUserInCreditNoteRole()" class="divider"></li>
<li><a data-ui-sref="showDaybook">Daybook</a></li>
<li class="divider"></li>
<li><a data-ui-sref="showCustomerLedger">Customer Ledger</a></li>
</ul>
</li>
At present the only way I can force the navbar to be refreshed is by doing a page refresh via F5, which proves that the role based system works, but I'd like it to work automatically by reloading the navbar.
Controller
'use strict';
appModule.controller('indexController', ['$scope', '$state', 'authService',
function ($scope, $state, authService) {
$scope.isAuthenticated = function () {
return authService.isAuthenticated();
};
$scope.isUserInCreditNoteRole = function () {
return authService.isAuthenticated() && authService.isUserInCreditNoteRole();
};
$scope.isUserInInvoiceRole = function () {
return authService.isAuthenticated() && authService.isUserInInvoiceRole();
};
$scope.isUserInOrderRole = function () {
return authService.isAuthenticated() && authService.isUserInOrderRole();
};
$scope.isUserInAdminRole = function () {
return authService.isAuthenticated() && authService.isInAdminRole();
};
}]);
Auth service
Here is the auth service with the relevant code. Bear in mind that the [roles.xxx] are just constants.
'use strict';
appModule.factory('authService', ['$http', 'roles',
function ($http, roles) {
var authServiceFactory = {};
var authentication = {
isAuth: false,
roles: "Anon"
};
var checkRoles = function (access) {
var result = false;
for (var a in access) {
console.log(access[a]);
for (var b in access[a]) {
if (authentication.roles.indexOf(access[a][b]) >= 0) {
result = true;
break;
}
}
if (result)
break;
}
console.log('result ' + result);
return result;
};
var isUserInInvoiceRole = function () {
return checkRoles([roles.invoice]);
};
var isUserInOrderRole = function () {
return checkRoles([roles.order]);
};
var isUserInCreditNoteRole = function () {
return checkRoles([roles.creditNote]);
};
var isInAdminRole = function () {
return checkRoles([roles.admin]);
};
var isAuthenticated = function () {
return authentication.isAuth;
}
authServiceFactory.isAuthenticated = isAuthenticated;
authServiceFactory.isUserInCreditNoteRole = isUserInCreditNoteRole;
authServiceFactory.isUserInInvoiceRole = isUserInInvoiceRole;
authServiceFactory.isUserInOrderRole = isUserInOrderRole;
authServiceFactory.isInAdminRole = isInAdminRole;
return authServiceFactory;
}]);
I have managed to resolve this myself after understanding how AngularJS watches updates to a controllers' scope.
I simply repopulated the authentication object in the authentication service, after a new refresh token had been retrieved and the nav bar updated instantly.
I use ngStorage (https://github.com/gsklee/ngStorage) for storing some data in the localStorage of the browser.
I have this markup
<ul class="cards">
<li ng-repeat="card in cards">
<card></card>
</li>
</ul>
With a "card" (as u can see) directive, that stores my template for each card.
In my Controller I have this method to push a card in the ng-repeat Array of cards:
angular.controller('CustomerController', function($scope, $localStorage, $sessionStorage) {
$scope.cards = [];
$scope.addCardRed = function() {
return $scope.cards.push(new Card("red"));
};
(...)
});
That works so far. But I can't accomplish to store the cards in my ul. I tried some variations of:
(...)
$scope.$storage = $localStorage;
$scope.cards = [];
$localStorage.cards = [];
$localStorage.cards = $scope.cards;
But either my cards won't displayed in the list anymore or the list won't be stored. What can I do to store my card elements in the list? What am I doing wrong?
I think, your Card is not a Simple JavaScript Object. therefore you may want to use something like this:
angular.module('storage',[]).factory('cardStorage',function(){
var key = 'cards';
var store = localStorage;
// Card has to be JSON serializable
function assign(value){store[key]=JSON.stringify(value)};
// return Card instances
function fetch(){return (JSON.parse(store[key])||[]).map(
function(card){return new Card(card);
})};
return {
bind:function(scope,attribute,defaults){
// read from storage - in case no data in scope
if(!(attribute in scope)){
scope[attribute]=fetch();
}
// observe changes in cars and persist them
scope.$watch(attribute,function(next,prev){
assign(next);
},true);
}
}
});
and in your Controller
function(scope,cardStorage){
cardStorage.bind('cards');
}
or you can use :
https://github.com/agrublev/angularLocalStorage