Search code examples
javascriptangularjsangularjs-directiveng-showangular-ng-if

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.


Solution

  • 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)