Angular-Formly: Interacting with multiple forms in multiple directives - javascript

i'm trying to figure out how to save and react on multiple forms in multiple directives.
To give you a short overview:
Screenshot of the current view
I've got three tabs containing forms and a fourth containing a JsTree (Groups). Each of the three tabs contains a directive, which, in turn, contains a Formly form.
The tabs are wrapped by a main directive which contains a footer directive with the save and cancel buttons in the bottom right corner.
Main directive:
/**
* Displays the ui for editing a specific user
*/
export function UserDetailsDirective() {
class UserDetailsDirective {
/*#ngInject*/
constructor(
$stateParams,
userService,
formlyChangeService
) {
this.currentUser = this.currentUser || {};
this.originalUser = this.originalUser || {};
this.userForms = {
mainData: {},
personalData: {},
basicSettings: {}
};
this.savingAllowed = true;
/* Second try: Registering a callback at the change service, which will be executed on any field change in the passed form (mainData) */
formlyChangeService.onFormChange('mainData', () => {
console.log('test123');
console.log('this123', this);
console.log('this.userForms.mainData.api.isValid()', this.userForms.mainData.api.isValid());
});
if ($stateParams.id > 0) {
userService.getUser($stateParams.id).then((userData) => {
userData.Birthday = new Date(userData.Birthday);
this.currentUser = userData;
this.breadcrumbData = [...];
})
}
}
onSave(controller) {
alert('on save');
console.log('controller', controller);
}
}
return {
restrict: 'E',
templateUrl: 'components/usermanagement/edit/user-details/user-details.directive.html',
controller: UserDetailsDirective,
controllerAs: 'controller',
bindToController: true
}
}
<breadcrumb [...]></breadcrumb>
<ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" data-target="#mainData">Account data</a></li>
<li><a data-toggle="tab" data-target="#personalData">Personal data</a></li>
<li><a data-toggle="tab" data-target="#basicSettings">Settings</a></li>
<li><a data-toggle="tab" data-target="#userGroupAssignment">Groups</a></li>
</ul>
<div class="row">
<div class="col-lg-6">
<div class="tab-content">
<div id="mainData" class="tab-pane fade in active">
<main-data user="controller.currentUser"></main-data>
</div>
<div id="personalData" class="tab-pane fade">
<personal-data user="controller.currentUser"></personal-data>
</div>
<div id="basicSettings" class="tab-pane fade">
<basic-settings user="controller.currentUser"></basic-settings>
</div>
<div id="userGroupAssignment" class="tab-pane fade">
<group-assignment user="controller.currentUser"></group-assignment>
</div>
</div>
</div>
<div class="col-lg-6">
[...] <!-- Right column -->
</div>
</div>
<!-- Footer -->
<user-details-footer
on-save="controller.onSave(controller)"
saving-allowed="controller.savingAllowed"
></user-details-footer>
Footer directive
/**
* Displays the user details footer
*/
export function UserDetailsFooterDirective() {
class UserDetailsFooterDirective {
/*#ngInject*/
constructor(
$state,
Notification,
$translate
) {
this.state = $state;
this.notification = Notification;
this.translate = $translate;
this.savingAllowed = this.savingAllowed || false;
}
/**
* Event that is triggered on save button click
*
* Propagates to the parent controller via attribute binding
*/
saveEvent() {
if (typeof this.onSave === 'function') {
this.onSave();
}
}
/**
* Navigates to the user list
*/
goToUserList() {
this.state.go('userList');
}
}
return {
restrict: 'E',
templateUrl: 'components/usermanagement/edit/user-details-footer/user-details-footer.directive.html',
controller: UserDetailsFooterDirective,
controllerAs: 'controller',
bindToController: true,
scope: {
onSave: '&?',
savingAllowed: '=?'
}
}
}
<nav class="navbar navbar-fixed-bottom">
<div class="container-fluid pull-right">
<button class="btn btn-default" ng-click="controller.goToUserList()"><i class="fontIcon fontIconX"></i> Cancel</button>
<button class="btn btn-primary" ng-disabled="controller.savingAllowed !== true" ng-click="controller.saveEvent()"><i class="fontIcon fontIconSave"></i> Save</button>
</div>
</nav>
First tab's directive
/**
* Displays the contents of the tab "Account data"
*/
export function MainDataDirective() {
class MainDataDirective {
/*#ngInject*/
constructor(
formlyFormService,
mainDataFieldProviders,
$state,
userSubmitService,
$timeout,
formlyChangeService,
$scope
) {
this.state = $state;
this.$timeout = $timeout;
this.userSubmitService = userSubmitService;
this.model = {};
this.originalUser = this.originalUser || {};
this.fields = [];
this.form = null;
var that = this;
/* Third try: Watching the form instance => partial success */
this.watch('formMainData', function(x, y, form) {
console.log('formMainData', form);
that.form = form;
form.watch('$invalid', function(foo, bar, value) {
/* This will react on field changes but it seems really dirty to me */
console.log('$invalid', arguments);
});
});
formlyFormService.getFormConfiguration(mainDataFieldProviders).then((result) => {
/* Here the formly fields are set */
this.fields = result;
/* Second try: A service which provides a callback that will be executed on field invalidation => no success */
formlyChangeService.registerFields(this.fields, 'mainData');
}, (error) => {
console.error('getMainDataFields error:', error);
});
this.api = {
isValid: angular.bind(this, this.isValid),
submit: angular.bind(this, this.onSubmit)
}
}
/* First try to get the validity of the fields => no success */
isValid() {
//return this.$timeout(() => {
let isValid = true;
this.fields.some((field) => {
if (
field.validation.errorExistsAndShouldBeVisible === true
|| field.validation.serverMessages.length > 0
) {
isValid = false;
return true;
}
});
//return isValid;
//}, 10);
return isValid;
}
/**
* Method triggered by the formSubmit event
*/
onSubmit() {
this.userSubmitService.submitUser(this.fields, this.model);
}
}
return {
restrict: 'E',
templateUrl: 'components/usermanagement/edit/main-data/main-data.directive.html',
controller: MainDataDirective,
controllerAs: 'controller',
bindToController: true,
scope: {
originalUser: '=user',
api: '=?'
},
link: (scope) => {
scope.$watch('controller.originalUser', (newValue) => {
if (newValue.hasOwnProperty('ID')) {
scope.controller.model = angular.copy(newValue);
}
});
}
}
}
<form name="controller.form" ng-submit="controller.onSubmit()" class="form-horizontal" novalidate>
<formly-form form="controller.formMainData" model="controller.model" fields="controller.fields" ></formly-form>
</form>
Second try: FormlyChangeService => got change event fired but before validation => no success
export /*#ngInject*/ function FormlyChangeService() {
let callbacks = [];
return {
triggerFormChangeEvent: triggerFormChangeEvent,
registerFields: registerFields,
onFormChange: onFormChange
};
function triggerFormChangeEvent(value, options) {
callbacks.forEach((callback) => {
if (
typeof callback === 'function'
&& callback.formDirective === options.templateOptions.formDirective
) {
callback();
}
});
}
function onFormChange(formDirective, callback) {
callback.formDirective = formDirective;
callbacks.push(callback);
}
function registerField(fieldConfig) {
fieldConfig.templateOptions.changeEvents.push(
triggerFormChangeEvent
);
}
function registerFields(fieldConfigs, formDirective) {
fieldConfigs.forEach((fieldConfig) => {
fieldConfig.templateOptions.formDirective = formDirective;
registerField(fieldConfig);
fieldConfig.watcher = {
listener: function() {
console.log('listener', arguments);
}
};
console.log('fieldConfig', fieldConfig);
fieldConfig.watch('$valid', function() {
console.log('valid field', arguments);
});
});
}
}
The Formly forms are fed with an user model, which is provided by the main directive.
I have to save all four tabs at the same time because there are several mandatory fields that have to be present to save the entered record.
Now here comes the tricky part:
I want the save button to be disabled if the model hasn't changed or an error occurred at any field in any form. I also want to know which form the error comes from.
What i thought about is an event or watcher in the Formly field config or something similar.
I've tried the onChange event on the field config but it is fired right before the field validation runs, so i won't get the current error status of that field.
The error status has to be passed up to the main directive from where it should be passed down to the save button.
Can anyone help me getting the forms (or even better the respective fields) to tell the main directive that there is an invalid field?
It's really difficult to exemplify such a complex task, so if there is any obscurity please let me know.
Thank you very much in advance.
Julian

I think you should have a service or factory that all your directive depend on that holds the data for all your forms.
This way you can set up a watch in your directive that will call whatever method on your shared service to validate / invalidate forms on your other tabs.
I hope this helps

Related

How to use a function from Component inside the page controller in AngularJS?

I want to use a function from a component inside my page.controller
First, I don't know if it is possible? and Second, if it is possible, how should I do that?
Here I have have function inside the component.controller called checkStatus, I want to execute it, therefore my ng-disabled turns false and I can click on SAVE button.
testComponent.component.js:
export default {
template: temp,
controller: myComponentController,
controllerAs: 'vm',
bindings: {
popupMsg : '&'
}
};
function myComponentController() {
'ngInject';
this.popupMsg = function() {
alert("It is working!");
this.checkStatus();
};
this.checkStatus = function() {
this.mustPass = true;
};
}
myPage.controller.js:
export class MyPageController {
constructor() {
'ngInject'
...
}
save() {
...
}
}
myPage.html:
<form>
<test-component mandatory="vm.popupMsg()"> </test-component>
<div>
<button type="submit" ng-click="vm.save()" ng-disabled="!vm.mustPass"> Save </button>
</div>
</form>
Plunker for testing
You need to have output bindings on your testComponent.
testComponent.component.js
bindings: {
statusChange: '&'
}
function myComponentController() {
this.checkStatus = function() {
this.mustPass = true;
this.statusChange({$event: this.mustPass});
};
mypage.html
<test-component mandatory="vm.popupMsg()" status-change="vm.onStatusChange($event)"> </test-component>

Angular uibModal, Resolve, Unknown Provider

I am trying to expose a "generic" modal - using Angular's $uibModal - through a service. Here is the definition of that service:
angular.module('app').service('CustomModalService', ['$uibModal', function ($uibModal) {
var openCustomModal = function (size, title, message) {
var actionToPerformOnConfirm = action;
var modalInstance = $uibModal.open({
templateUrl : 'templates/CustomModal.html',
size: size,
resolve: {
title: title,
message: message
}
});
};
return {
openCustomModal: openCustomModal
};
}]);
Nothing too complicated, above. However, it is not working. If I remove the resolve property from the object, the service works; however, if I include the resolve property, I get the Unknown Provider error originating from that property.
The documentation for the resolve property reads:
(Type: Object) - Members that will be resolved and passed to the
controller as locals; it is equivalent of the resolve property in the
router.
The objective is to be able to provide a template for the modal that utilizes these properties in its DOM, e.g. :
<div ng-controller="CustomModalController">
<div class="modal-header">
<h3 class="modal-title">{{title}}</h3>
</div>
<div class="modal-body">
{{message}}
</div>
<div class="modal-footer">
<button class="ad-button ad-blue" type="button" ng-click="confirmAction()"></button>
<button class="ad-button ad-blue" type="button" ng-click="cancelAction()"></button>
</div>
</div>
What am I missing that is causing this error to be thrown?
You have two problems:
You need to define the controller in your modal config
Your resolve object needs to be a map of string: function, where string is the name of the dependency that will be injected into your modal's controller, and function is a factory function that will be used to provide that dependency when the controller is instantiated.
Working example: JSFiddle
JavaScript
angular.module('myApp', ['ui.bootstrap'])
.controller('MyModalController', MyModalController)
.directive('modalTrigger', modalTriggerDirective)
.factory('$myModal', myModalFactory)
;
function MyModalController($uibModalInstance, items) {
var vm = this;
vm.content = items;
vm.confirm = $uibModalInstance.close;
vm.cancel = $uibModalInstance.dismiss;
};
function modalTriggerDirective($myModal) {
function postLink(scope, iElement, iAttrs) {
function onClick() {
var size = scope.$eval(iAttrs.size) || 'lg'; // default to large size
var title = scope.$eval(iAttrs.title) || 'Default Title';
var message = scope.$eval(iAttrs.message) || 'Default Message';
$myModal.open(size, title, message);
}
iElement.on('click', onClick);
scope.$on('$destroy', function() {
iElement.off('click', onClick);
});
}
return {
link: postLink
};
}
function myModalFactory($uibModal) {
var open = function (size, title, message) {
return $uibModal.open({
controller: 'MyModalController',
controllerAs: 'vm',
templateUrl : 'templates/CustomModal.html',
size: size,
resolve: {
items: function() {
return {
title: title,
message: message
};
}
}
});
};
return {
open: open
};
}
HTML
<script type="text/ng-template" id="templates/CustomModal.html">
<div class="modal-header">
<h3 class="modal-title">{{vm.content.title}}</h3>
</div>
<div class="modal-body">
{{vm.content.message}}
</div>
<div class="modal-footer">
<button class="ad-button ad-blue" type="button" ng-click="vm.confirm()">
confirm
</button>
<button class="ad-button ad-blue" type="button" ng-click="vm.cancel()">
cancel
</button>
</div>
</script>
<button modal-trigger size="'sm'" title="'Hello World!'" message="'This is a test'">
Click Me
</button>

ng-show - using a service as a scope parameter

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;
};
});

Call 2 functions in single ng-click

I am calling two functions on ng-click. But it doesn't work. I am not sure why the Refresh1() is not called when I cross-checked through debugger.
HTML CODE
<div class="row" ng-controller="PublishManifestCtrl">
<div class="col-xs-12 col-md-12">
<div class="widget">
<div class="widget-header bordered-bottom bordered-themeprimary">
<i class="widget-icon fa fa-tasks themeprimary"></i>
<span class="widget-caption themeprimary">Manifest Status</span>
</div>
<div class="widget-body">
<form class="form-bordered" role="form">
<div class="form-group">
<label style="padding-left: 8px;">Manifest was last published to agents on <b>{{manifeststatus.manifestLastPublishedDate}}</b>.</label>
</div>
<div class="form-group">
<label style="padding-left: 8px;">Manifest was last updated by <b> {{manifeststatus.lastUpdatedByUser}} </b> on <b>{{manifeststatus.manifestLastedUpdatedDate}}</b>.</label>
</div>
<div class="form-group">
<div class="col-sm-offset-1">
**<button id="PublishButton" class="btn btn-default shiny " ng-disabled="manifeststatus.enablePublishButton" ng-click="Save(manifeststatus);Refresh1()">Publish</button>**
</div>
<br/>
<div id="statusDivPublish" ng-show="showstatus">
<alert type="{{alert.type}}">{{alert.msg}}</alert>
</div>
</div>
</form>
</div>
JSFILE
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
}
$scope.Refresh1 = function () {
//refresh
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
}
});
new code
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.Refresh1();
}
$scope.Refresh1 = function ($rootScope, $state, $stateParams) {
debugger;
return {
restrict: 'AC',
link: function (scope, el, attr) {
el.on('click', function () {
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
});
}
};
};
});
The first one updates and displays a successfull message, while the second function refreshes the page.
use this
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.refresh();
}
call refresh inside the first function and remove it from the ng-click.
Update
You have a different type of problem i had it too. you try to refresh a state inside a method, it's really difficult i solve that problem with this snippet
if($state.current.name == /*name of the current state*/) {
$state.go($state.current, {}, {reload: true});
$modalInstance.close();
}
else {
$modalInstance.close();
$state.go(/*name of the current state*/);
}
it's not difficult but it didn't behave like you have understand it.
UPDATE
taking your code
$scope.Refresh1 = function () {
//refresh
$state.go($state.current, {}, {reload: true});
}
What about calling refresh inside of save in $http handler ?
Like this:
$http.post($rootScope.WebApiURL + '/updatemanifeststatus')
.then(function(){
$scope.Refresh1();
});
Don't execute two function in one ng-click, instead add the Refresh1 call to the end of the Save call, like so.
HTML
<button id="PublishButton"
class="btn btn-default shiny "
ng-disabled="manifeststatus.enablePublishButton"
ng-click="Save(manifeststatus)">Publish</button>
JS
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.refresh();
}
Update
If you are using AngularJS V1.2.2 or higher, then using ui-router, the following should work to reload the data.
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
The shortest way to accomplish this though would be with:
$state.go($state.current, {}, {reload: true}); //second parameter is for $stateParams
Its also worth noting that none of these will actually reload the page. If you want to reload the state AND the page, there is no ui-routermethod for it. Do window.location.reload(true)
Update 2
If you are receiving:
$state is not defined at Scope.$scope.Refresh1
(publishmanifest.js:44) at Scope.$scope.Save (publishmanifest.js:37)
at $parseFunctionCall (angular.js:12345) at angular-touch.js:472 at
Scope.$eval (angular.js:14401) at Scope.$apply (angular.js:14500) at
HTMLButtonElement. (angular-touch.js:471) at
HTMLButtonElement.n.event.dispatch (jquery.min.js:3) at
HTMLButtonElement.r.handle (jquery.min.js:3)
You are not injecting the $state service in your controller. You must do this in order to use it.
//without annotation (inferred, not safe when minifying code)
function Controller($scope, $state) {...}
//inline annotation
module.controller('Controller', ['$scope','$state', function($scope, $state) {...}]);
//$inject property annotation
function Controller($scope, $state) {...}
Controller.$inject = ['$scope', '$state'];
Pick one of the methods above to setup your controller to use $state.
Just make a third function like:
function3(data) {
save(data);
refresh1();
}

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