ng-show - using a service as a scope parameter - javascript

I'm writing an angular 1.5.0-rc0 application using bootstrap for a nav bar component.
I want to show the user an added items to his navigation bar if his user group id is 1.
first I created a service:
app.factory('UserService', function() {
return {
userGroupId : null
};
});
I created the nav bar as a directive, so i included it in the main html file
<nav-bar></nav-bar>
and the nav-bar directive code:
(function () {
angular.module('myalcoholist').directive('navBar', function () {
return {
restrict: 'E',
templateUrl: 'views/nav.html',
controller: ['$scope','$auth', 'UserService',function ($scope,$auth,UserService) {
$scope.user=UserService;
$scope.isAuthenticated = function()
{
return $auth.isAuthenticated();
};
}]
}
});
})();
as you can see I set $scope.user as the returned object from UserService.
in my login controller, after a successful login I set the userGroupId.
angular.module('myalcoholist').controller('LoginController',['$scope','$auth','$location', 'toastr','UserService',function ($scope,$auth,$location,toastr,UserService) {
$scope.authenticate = function (provider) {
$auth.authenticate(provider).then(function (data) {
var accessToken = data.data.token;
apiKey=accessToken;
UserService.userGroupId=data.data.user_group_id;
...
now.. my nav-bar template file is as the following code:
<li ng-show="user.userGroupId == 1">
Admin Drinks
</li>
even after the authentication, when I uset userGroupId to 1 the element is still not shown.
any ideas?
update
I debugged and noticed that UserService.userGroupId is still null. so
I changed the UserService to have the following code:
app.factory('UserService', function() {
var user = {userGroupId:null};
return {
setUserGroupId: function (userGroupId) {
user.userGroupId=setUserGroupId;
},
getUserGroupId: function () {
return user.userGroupId;
}
};
});
in my LoginController I now try to execute setUserGroupId:
angular.module('myalcoholist').controller('LoginController',['$scope','$auth','$location', 'toastr','UserService',function ($scope,$auth,$location,toastr,UserService) {
$scope.authenticate = function (provider) {
$auth.authenticate(provider).then(function (data) {
var accessToken = data.data.token;
apiKey=accessToken;
UserService.setUserGroupId(data.data.user_group_id);
...
when I debug i see that userService is an object with two functions as I defined, but when the javascript chrome debugger tries to execute this line:
UserService.setUserGroupId(data.data.user_group_id);
I get the following error:
ReferenceError: setUserGroupId is not defined
at Object.setUserGroupId (app.js:21)
at login-controller.js:12
at angular.js:15287
at m.$eval (angular.js:16554)
at m.$digest (angular.js:16372)
at m.$apply (angular.js:16662)
at g (angular.js:11033)
at t (angular.js:11231)
at XMLHttpRequest.v.onload (angular.js:11172)

I have created a fiddle showcasing your requirement (as close as possible), and it seems to work fine.
http://jsfiddle.net/HB7LU/21493/
My guess is that you aren't actually setting the value when you think you are, and will likely require some debugging. Here is the code for brevity.
HTML
<div ng-controller="MyCtrl">
<div ng-click="clicked()">
Click ME, {{user.value}}!
</div>
<test-dir></test-dir>
</div>
JS
angular.module('myApp',[])
.service('TestService', function(){
return {
value: 2
};
})
.directive('testDir', function(){
return {
restrict: 'E',
template: '<div ng-show="user.value === 1">Here is some text</div><div>Some more always showing</div>',
controller: function ($scope, TestService) {
$scope.user = TestService;
}
};
})
.controller('MyCtrl', function($scope, TestService){
$scope.user = TestService;
$scope.clicked = function(){
TestService.value = 1;
};
});

Related

Detail Page View not Showing Data in ionic

I'm new to Ionic. I write code for list. List is working perfectly but when click on any list-item it's not showing any data.
It showing me this error "Cannot GET /pilliondetails/1" how can i solve this?
app.factory('myService', function() {
var savedData = {}
function set(data) {
savedData = data;
console.log(savedData);
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
})
PillionList Controller:
.controller('PillionListCtrl',function($scope,$ionicHistory,myService){
$scope.myGoBack = function() {
$ionicHistory.goBack();
};
$scope.pillions = [];
var promise=myService.get();
$scope.pillions=myService.get();
})
PillionDetail Controller:
.controller('PillionDetailCtrl',function($scope, $ionicHistory, $stateParams, myService)
{
$scope.myGoBack = function() {
$ionicHistory.goBack();
};
var promise=myService.get($stateParams.requestId);
console.log(promise);
})
PillionList.html :Showing list pf Pillions
<ion-list>
<ion-item data-ng-repeat="pillion in pillions">
<div class="list list-inset">
{{pillion.request_departure_date}}-{{pillion.request_departure_time}}
{{pillion.request_from}} >> {{pillion.request_to}}
{{pillion.user_first_name}} {{pillion.user_last_name}}
<a ui-sref="pilliondetails({pillionId:pillion.request_id})" nav-direction="enter">
<h2>More Details...</h2>
</a>
</div>
</ion-item>
</ion-list>
my app.js
.state('pillionlist', {
url: '/pillionlist',
templateUrl: 'templates/pillionlist.html',
controller: 'PillionListCtrl'
})
.state('pilliondetails', {
url: '/pillionlist/:pillionId',
templateUrl: 'templates/pilliondetails.html',
controller: 'PillionDetailCtrl'
})
Its redirecting to pillionDetail view but not showing data.
Please help.
The first thing i noticed is
ui-sref="pilliondetails({pillion.request_id})"
it should be key-value pair like this
ui-sref="pilliondetails({ your_id : pillion.request_id})"
and in stateProvider, the url of details page should contain parameter. for eg.
url : '/pilliondetails/:your_id'

Problems with ng-repeat, $scope, $http

im working with AnuglarJS 1.4.8. I want give out the data with ng-repeat.
I have the following problem and i have no more ideas to solve it. I tried the solutions from AnuglarJS but i doesnt work.
Could someone help me please.
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
http://errors.angularjs.org/1.4.8/$rootScope/infdig?p0=10&p1=%5B%5D
Service:
.service('database', function ($http) {
self = this;
this.url = 'http://localhost:3001';
this.getPersons = function(cb){
return $http({
method: 'GET',
url: self.url + '/loadperson'
}).success(function (data) {
cb(data);
});
};
});
Controller:
angular.module('myApp')
.controller('personCtrl', function ($scope, database) {
$scope.people = function(){
return{
getAll: function () {
database.getPersons(function (data) {
return data;
// should return a Object(id, name)
});
}
}
};
HTML:
<div ng-repeat="people in people().getAll()">
<p>{{people.name}}</p>
</div>
You are missing the non-blocking way of javascript. Try following, it should work
Controller:
angular.module('myApp')
.controller('personCtrl', function ($scope, database) {
$scope.loadPeoples = function(){
return{
getAll: function () {
database.getPersons(function (data) {
$scope.peoples = data;
// should return a Object(id, name)
});
}
}
};
$scope.loadPeoples();
})
HTML:
<div ng-repeat="people in peoples">
<p>{{people.name}}</p>
</div>
Try that.
Service:
.service('database', function ($http) {
self = this;
this.url = 'http://localhost:3001';
this.getPersons = function(){
return $http({
method: 'GET',
url: self.url + '/loadperson'
});
};
});
Controller:
angular.module('myApp')
.controller('personCtrl', function ($scope, database) {
database.getPerson().success(function(data) {
$scope.people = data;
});
});
HTML:
<div ng-repeat="person in people">
<p>{{person.name}}</p>
</div>
You should also be aware that you shouldn't return each time a NEW array for iterating. Otherwise angular will keep calling that function for retrieving a "stable" value for the array.
You've made a common error in javascript when running asynchronous queries. The pattern goes:
function outerFunction() {
invokeInnerFunction(function() {
return 3;
}
}
What does outerFunction() return? An error is to think it returns 3, but the answer is actually that outerFunction doesn't return anything.
Likewise, in your example getAll isn't actually returning anything; it's just calling an asynchronous method. This asynchronous method invoked $http, which triggers a digest loop which will result in getAll being called again, and so on for ever. Be thankful that angular can detect this problem.
You only want to call the database query once on startup, and initialize the list of people. Simply store this list in a variable so it won't query the database again on the next digest loop.
angular.module('myApp')
.controller('personCtrl', function ($scope, database) {
$scope.allPeople = [];
database.getPersons(function(data) {
$scope.allPeople = data;
});
};
An then for your HTML
<div ng-repeat="people in allPeople">
<p>{{people.name}}</p>
</div>
Much simpler.
Have you tried making a separate function to fetch the entities from the data base, then put this data in a variable, that you then will pass to the ngRepeat ?
your controller
angular.module('myApp')
.controller('personCtrl', function ($scope, database) {
$scope.people = [];
$scope.getPeople = function(){
return{
getAll: function () {
database.getPersons(function (data) {
$scope.people = data;
return;
// should return a Object(id, name)
});
}
}
//load the list of people
$scope.getPeople();
};
your view
<div ng-repeat="person in people">
<p>{{person.name}}</p>
</div>

Angular, queuing ng-init

Is it possible queuing ng-init?
Generally, in first init I want to add JSON file to prototype vars (array) and in another init depending on the params I want to skip getJsonData() or add other JSON file to prototype.
function init(param) {
console.log("startInit");
// big JSON file
var promise = getJSON(param);
return promise.then( function() {
//some func
console.log("finish");
return true;
});
};
function getJSON(param) {
var deferred = $q.defer();
console.log("startInitDataInner");
someService.getJsonData(param).then(function(data) {
// some code
console.log("endInitDataInner");
deferred.resolve();
}, function(error) {
deferred.reject();
});
return deferred.promise;
};
in view ng-init
ng-init="init(param)"
ng-init="init(param)"
// ...
and log:
startInit
startInitDataInner
startInit
startInitDataInner
endInitDataInner
finish
endInitDataInner
finish
//..
Edit:
Generally, I want to create something like plugin in jQuery. I have this code:
<div ng-controller="parentController as parent">
<div ng-controller="childController as child" ng-init="child.init(parent.data)"></div>
</div>
<div ng-controller="parentController as parent">
<div ng-controller="childController as child" ng-init="child.init(parent.data2)"></div>
</div>
and configurable part by user:
angular.module('myApp').controller('parentController', ['$scope', function($scope) {
this.data = {
config: {
lang: "en",
title: "title"
}
};
this.data2 = {
config: {
lang: "pl",
title: "title2"
}
};
}]);
ng-init update api:
angular.extend(this, parent.data);
Do you have any ideas how I should do it differently?
Well, if you are working with angular, you use controllers. What is controller itslfmin general meaning? Right, its a constructor function. The main word here is function. What does function in general? Run the code inside.
So, just place your initial logic at the beggining of controller code (but without wrapping it as a separate function) and it will run just in time your controller will be resolved by angular resolver.
var controller = function () {
// vars, costs, etc.
console.log("startInit");
// big JSON file
var promise = getJSON(param);
return promise.then( function() {
//some func
console.log("finish");
return true;
});
};

Best way to integrate captcha in angularJS

I'm relatively new to angularJS and I wonder what would be the cleanest solution to the following problem.
Let's say I have a form such as follows
<form name="contactform">
<select id="salutation" name="salutation" required="true" ng-model="contactRequest.salutation"><option value="Herr" selected="">Herr</option><option value="Frau">Frau</option></select>
<img width="255" height="70" alt="" src="/website/var/tmp/aed4d639a26c4614cdac2a967381c61c.png" name="captcha[img]">
<captcha-reloader reload-url="/refresh-captcha" img-tag-name="captcha[img]" hidden-field-name="captcha[id]"></captcha-reloader>
<input type="text" name="captcha[input]" required="true" ng-model="contactRequest.captcha.input">
<input type="text" style="display: none;" ng-model="contactRequest.captcha.id" value="aed4d639a26c4614cdac2a967381c61c" name="captcha[id]">
...
As you can see, it uses a directive to display a button which will reload the CAPTCHA. It is defined as
myApp.directive('captchaReloader', function () {
return {
restrict: 'E',
scope: {
reloadUrl: '#',
imgTagName: '#',
hiddenFieldName: '#'
}, //isolate scope
template: '',
link: function (scope, element, attrs) {
},
controller: function ($scope, $element, $attrs, $http) {
$scope.reloadCaptcha = function () {
$http.get($attrs.reloadUrl).then(function (res) {
angular.element('img[name="' + $attrs.imgTagName + '"]').attr('src', res.data.imgSrc);
angular.element('input[name="' + $attrs.hiddenFieldName + '"]').val(res.data.id);
angular.element('input[name="' + $attrs.hiddenFieldName + '"]').trigger('input');
});
};
}
};
)};
If I click on the button, the captcha image and value (hidden field) are updated. It works fine so far.
Now, I want to handle form submission in controller (see methode below). If there is an error (server-side validation), the captcha has to be updated. I don't know whats the best way to trigger the updated-process defined in the directive. Can anyone help?
myApp.controller('KontaktCtrl', function ($scope, $location, CustomerDataService, CaptchaService) {
$scope.contactRequest = {
salutation: 'Herr',
captcha: {
id: initialCaptchaId
}
};
$scope.errors = {};
$scope.submitAction = function () {
CustomerDataService.sendRequest($scope.contactRequest).then(function (res) {
var data = res.data;
if (res.data.data !== null) { //errors in form. Display them
//error handling
$scope.reloadCaptcha();
} else {
goToHomeView();
}
}, function (error) {
console.log('An error occurred while updating!', error);
});
};
var goToHomeView = function () {
$location.path('/');
};
});
Additionally, I have to init the values of select-box and captcha, cause otherwise they are not sent (because the are untouched). Is there any way to avoid this?
PS: I found a reCAPTCHA directive, but reCAPTCHA is no option due to styling limitations.
Its very simple follow the steps...
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit"
async defer></script>
<script>
var onloadCallback = function() {
widgetId1 = grecaptcha.render('example1', {
'sitekey' : 'Site-Key-',
'theme' : 'light'
});
};
</script>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit"
async defer>
Now at the form put it
<div id="example1"></div>
<p style="color:red;">{{ captcha_status }}</p>
Validate with angular
if(grecaptcha.getResponse(widgetId1)==''){
$scope.captcha_status='Please verify captha.';
return;
}

How to show buttons with user authentication in AngularJS?

Currently I am working on my master project. My application is online portfolio management. User can register on app and create profiles. Now i want to give Edit and Delete buttons on the profile view. But just the users who have created the profile are able to see this buttons. For example, if i am a user of app then only i can see the edit and delete buttons on my profile and i can only see the other user's profile.
I am new in AngularJS. It looks easy but still did not work for me. I have a different views of view profile and edit profile. But i have just one controller for both of it.
This is how my view profile code looks like,
HTML
<section data-ng-controller="ProfilesController as profilesCtrl">
<div class="modal-header">
<div>
<h1>{{profile.firstname}} {{profile.lastname}}</h1>
</div>
<div class="pull-right">
<button class="btn-success btn-lg" type="button" data-ng-click="profilesCtrl.modalUpdate('lg', profile)">Edit</button>
<button class="btn-danger btn-lg" type="button" data-ng-click="profilesCtrl.remove(profile)">
<i class="glyphicon glyphicon-trash">
</i>
</button>
</div>
</div>
</section>
Controller
profilesApp.controller('ProfilesController', ['$scope', '$stateParams', '$location', 'Authentication', 'Profiles', '$modal', '$log',
function($scope, $stateParams, $location, Authentication, Profiles, $modal, $log) {
this.authentication = Authentication;
// Find a list of Profiles
this.profiles = Profiles.query();
// open a modal window to view single profile
this.modalview = function(size, selectedProfile) {
var modalInstance = $modal.open({
templateUrl: 'modules/profiles/views/view-profile.client.view.html',
controller: function($scope, $modalInstance, profile) {
$scope.profile = profile;
console.log(profile);
$scope.ok = function() {
$modalInstance.close($scope.profile);
};
},
size: size,
resolve: {
profile: function() {
return selectedProfile;
}
}
});
modalInstance.result.then(function(selectedItem) {
$scope.selected = selectedItem;
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
};
// open a modal window to update single profile
this.modalUpdate = function(size, selectedProfile) {
var modalInstance = $modal.open({
templateUrl: 'modules/profiles/views/edit-profile.client.view.html',
controller: function($scope, $modalInstance, profile) {
$scope.profile = profile;
$scope.ok = function() {
$modalInstance.close($scope.profile);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
},
size: size
});
modalInstance.result.then(function(selectedItem) {
$scope.selected = selectedItem;
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
};
// Remove existing Profile
this.remove = function(profile) {
if (profile) {
profile.$remove();
for (var i in this.profiles) {
if (this.profiles[i] === profile) {
this.profiles.splice(i, 1);
}
}
} else {
this.profile.$remove(function() {
$location.path('modules/profiles/views/list-profiles.client.view.html');
});
}
};
// Update existing Profile
this.update = function(updatedProfile) {
var profile = updatedProfile;
profile.$update(function() {}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
}
]);
Please suggest me some way, how can i fix this issue? Any help would appreciated.
you can use a directive like this:
<button access-level="canEdit">Edit</button>
and your directive is bound to accessLevel:
angular.module("app")
.directive('accessLevel', ['AuthService', 'AUTH_EVENTS', function (authService, authEvents) {
return {
restrict: 'A',
link: function ($scope, element, attrs) {
var accessLevel;
attrs.$observe('accessLevel', function (acl) {
if (acl) {
accessLevel = acl;
updateCss();
}
});
$scope.$on("auth-change", function (event, data) {
switch (data) {
case authEvents.logoutSuccess:
case authEvents.loginSuccess:
updateCss();
break;
case authEvents.notAuthorized:
default:
}
});
function updateCss() {
if (accessLevel) {
if (!authService.isAuthorized(accessLevel)) {
switch (element[0].nodeName) {
case "A":
element.hide();
break;
default:
element.attr("disabled", "disabled");
break;
}
} else {
switch (element[0].nodeName) {
case "A":
element.show();
break;
default:
element.removeAttr("disabled");
break;
}
}
}
}
}
}
}]);
this is a little bit more than what you need, but gives you an idea what you can achieve. (and you have to write your auth service etc.)
as example here is a part of my auth service:
angular.module('app')
.factory("AuthService", ["$rootScope", "$http", "AuthSession", "AUTH_EVENTS", function ($rootScope, $http, AuthSession, AUTH_EVENTS) {
AuthSession.load();
$rootScope.$on('$stateChangeStart', function (event, nextState) {
if (nextState.data && nextState.data.accessLevel && !service.isAuthorized(nextState.data.accessLevel)) {
event.preventDefault();
$rootScope.$broadcast('auth-change', AUTH_EVENTS.loginRequired, nextState.name);
}
});
var service = {
login: function (credentials) {
return $http
.post('/api/account/login', credentials)
.success(function (data, status) {
if ((status < 200 || status >= 300) && data.length >= 1) {
$rootScope.$broadcast("auth-change", AUTH_EVENTS.loginFailed);
return;
}
AuthSession.create(data.AccessToken, data.User);
$rootScope.$broadcast("auth-change", AUTH_EVENTS.loginSuccess);
}).error(function (data, status) {
$rootScope.$broadcast("auth-change", AUTH_EVENTS.loginFailed);
});
},
logout: function () {
AuthSession.destroy();
$rootScope.$broadcast("auth-change", AUTH_EVENTS.logoutSuccess);
},
isAuthenticated: function () {
return (AuthSession.token !== null);
},
isAuthorized: function (accessLevel) {
if (!accessLevel) return true;
return (this.isAuthenticated() && AuthSession.user.UserRoles.indexOf(accessLevel) !== -1);
}
}
return service;
}]);
this service retrieves a bearer token from the server and stores it in the authsession service. the user roles are also stored beside of other user information. since the backend is also secured, one who changes the user roles on the client, can't write to the backend. (everything on client side is just for the look and feel of the user)
Two ways :
Once the profile is created, let the isProfileCreated (you need to make one) column in user details table be updated. On angular load, call and check whether is profile created. use ng-show to show (edit and delete button)if it is true.
Or else, if you are going to edit, anyways you need to get the profile details from the table. in that case, let your server send a false if no profile is created or an json object if created.
In your controller use
if(angular.isObject(profile)){
$scope.showeditbutton = true;
$scope.showdeletebutton = true;
}

Categories