The `$scope variable fails to update in another controller`

I am currently facing an issue with updating a value on my view. Let me walk you through my code along with a brief explanation of the situation. The code may look messy as I have been experimenting with different combinations lately.

The controller in question is accCtrl:

controllers.accCtrl = function($scope, sessionFactory){
    sessionFactory.isLoggedIn().then(function(data){
        console.log(data.logged_in);
        $scope.loggedIn = data.logged_in;
    });
    $scope.logOut = function(){
        sessionFactory.logOutUser().then(function(data){
            $scope.loggedIn = data.logged_in;
        });
    }
}

The console log output shows false, and the variable $scope.loggedIn controls the display of login, register, profile, and logout buttons in my HTML.

<div ng-controller="accCtrl">
    {{loggedIn}}
        <ul>
        <li ng-hide="loggedIn">
            <a href="#/login">
                <b>Login</b>
            </a>
        </li>
        <li ng-hide="loggedIn">
            <a href="#/register" >
                <b>Register</b>
            </a>
        </li>
        <li ng-show="loggedIn" >
            <a href="#/my_profile">
                <b >My profile</b>
            </a>
        </li>
        <li ng-show="loggedIn"> 
            <a ng-click="logOut()">
                <b>Log out</b>
            </a>
        </li>
    </ul>
</div>

When a user tries to login by clicking the login button, the login form is shown. This functionality is handled in loginCtrl:

    controllers.loginCtrl = function($scope, $http, $location, $timeout, sessionFactory){
    $scope.loginUser = function () {
        $http({
            method: 'POST',
            url: $location.protocol() + '://' + $location.host() + '/server/api/users/login',
            headers: {'Content-Type': 'application/x-www-form-urlencoded'},
            data : $.param({
                username : $scope.username,
                password : $scope.password
            })
        }).success(function(data){
                sessionFactory.isLoggedIn().then(function(data){
                    $scope.loggedIn = data.logged_in;
                });
                window.location.href="/#/home";
        });
    };
}

After a successful login, the user is redirected to the home page. However, the issue arises when the $scope.loggedIn variable in the account controller is not updated despite the console.log(data.logged_in) in loginCtrl showing true.

Logging out works fine because it calls a function within accCtrl. The problem only occurs during login since it's handled in a different controller.

Below is my sessionFactory for reference:

app.factory('sessionFactory', ['$http', '$location', function($http, $location){
    var factory = {};

    factory.logOutUser = function(){
        return $http({
            method: 'GET',
            url: $location.protocol() + '://' + $location.host() + '/server/api/users/logout'
        }).then(function successCallback(response){
            return response.data;
        },function errorCallback(response) {
            console.log('error logging out: ' + response);
        });
    }
    factory.isLoggedIn = function(){
        return $http({
            method: 'GET',
            url: $location.protocol() + '://' + $location.host() + '/server/api/users/isLoggedIn'
        }).then(function successCallback(response){
            console.log(response.data);
            return response.data;
        },function errorCallback(response) {
            console.log('Checking login failed: ' + response);
        });
    }

    return factory;
}]);

Here's a snippet from my app.js file:

var app = angular.module('app', ['ngRoute', 'ngAnimate', 'ui.sortable', 'ngFileUpload'])
app.config(function($routeProvider){
    $routeProvider.
    when('/', {controller:'homeCtrl', templateUrl:'app/templates/home.html'}).
    (other routes listed here...)
});

I believe I need to implement some sort of watch or similar function, but I'm unsure how to proceed. Any help would be greatly appreciated.

TLTR

When a user logs in using loginCtrl, I need to update the $scope.loggedIn value in accCtrl.

If more information is needed, please let me know.

Answer №1

The issue arose from the fact that in AngularJS, controllers are only initialized once unless specifically set to reinitialize. When alerting something in the accCtrl, it will only alert once even if you visit the page multiple times. Pressing ctrl+f5 worked because it reset your controller. An easy way to reinitialize the controller is by using $window.location.reload(). This not only reloads the controller but also the services. Since you are using ngRoute, the best option to reinitialize your controller might be to use $window.location.reload();

.success(function(data){
                sessionFactory.isLoggedIn().then(function(data){
                    $scope.loggedIn = data.logged_in;
                });
                window.location.reload(); //the only workaround i could find with ngroute as for now.
                window.location.href="/#/home";
        });

However, when using ui.Router or $stateProvider, you have the ability to only reinitialize your controller like this:

.state('home', {
    url: '/home',
    templateUrl: 'templates/home.html',
    controller: 'accCtrl',
    reload: true //will reload controller when state is being access
});

$state.transitionTo($state.current, {}, { reload: true, inherit: true, notify: true });

and

$state.go('.', null, { reload: true });

This should solve the problem of reinitializing the controller mentioned in your question.

Answer №2

Hey, there are a couple of mistakes in your approach to the $scope.loggedIn variable.

1) It seems like you're getting confused because there is a false and true value being logged for $scope.loggedIn; This is due to the asynchronous nature of promises, causing the code to continue running even after requesting the session to log in.

sessionFactory.isLoggedIn().then(function(data){
    console.log(data);                     (2)
    $scope.loggedIn = data.logged_in;
    console.log($scope.loggedIn);          (3)
});
console.log($scope.loggedIn);              (1) <-- this executes first before the promise resolves
window.location.href="/#/home";

The last log statement appears first in order, but executes false initially since the user wasn't logged in before the promise started. Once the promise resolves, it will display the correct data as true. You can learn more about promises here and here.

2) Another mistake lies in changing angular variables with ajax requests without informing Angular when making scope changes outside of its framework. To handle this, Angular provides a mechanism by explicitly calling a digest cycle using $rootScope.$apply() or $scope.$apply(). It's recommended to implement this in your service. If you wish to use it in the controller, something like this should suffice:

$http({
    method: 'POST',
    url: $location.protocol() + '://' + $location.host() + '/server/api/users/login',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data : $.param({
        username : $scope.username,
        password : $scope.password
    })
}).success(function(data){
    ...
    $rootScope.$apply();
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Manipulating time formatting within an array with the help of moment.js, AngularJS, and lodash

I am working with JSON data that includes timings based on dates. obj = { "2017-12-08": [ "2017-12-08T13:00:00+0530", "2017-12-08T15:00:00+0530", "2017-12-08T15:30:00+0530", "2017-12-08T16:00:00+0530" ], "2017-12-09": [ "2017-12-09T09: ...

Emulate the CSS hover effect with jQuery 코드 희미한

Is there a method in jquery or any other technology that can detect event X and trigger a different event elsewhere? Currently, I am working with an image that has an image map. When a user hovers over a specific area on the map, I would like another part ...

Increase the value of (N) in the copied MongoDB file name

Are there any algorithms available to handle incrementing numbers in duplicate filenames? For instance, let's consider a simple collection of documents stored in a file collection: [ { "_id": "612ead8668bfcc4221a788f6" ...

A Bluebird promise was generated within a NodeJS handler function, however it was not properly returned from the function

Below is the nodejs code for an express middleware function: Middleware.is_authenticated = function(req, res, next) { if(req.system_session == undefined || req.system_session.login_status == false) return res.status(401).send({errors: true, error: &ap ...

Is there a way to trigger an animation after the completion of ng-repeat binding?

Check out this plunker that demonstrates an interesting behavior: the class ng-hide is removed from a tag before ng-repeat has finished creating the HTML view of the data. This results in the height of the element not being final when removeClass is trigge ...

When the jQuery Div is moved to the right, it gradually shrinks in size, yet remains unchanged when

I have been making updates to this page, which you can view here. When you select "Let's Get Started" and then proceed with the right arrows, the divs smoothly move to the left without shrinking. However, when clicking on the back or left arrows, the ...

Encountered an error while attempting to access the 'type' property of undefined within the Redux store for an action defined in an external package

In my quest to expand my knowledge of React (coming from an ASP.NET background), I encountered a challenge. I have multiple React applications where I intend to utilize common UI components, so I decided to extract these into a separate npm package. This a ...

What is the best method for creating and passing a wrapped component to React Router?

I have multiple routes that I need to render different components for, and I want each component to be wrapped in a styled div. However, I'm looking for a way to write this code more efficiently. Is there a strategy to refactor this so that I can eas ...

Obtaining an identification using JQuery for content that is constantly changing

I am currently developing dynamic content tabs using PHP, with one of the objects being a datatable within the tab. In order to define the ID via PHP, I use the following code: PHP: echo '<table class="table table-striped table-bordered table-hov ...

Can scrollHeight ever be less than clientHeight or offsetHeight?

Is it guaranteed that the output of Math.max(el.scrollHeight, el.offsetHeight, el.clientHeight) will always be equal to el.scrollHeight? Typically, clientHeight <= offsetHeight <= scrollHeight. While there are rare instances where clientHeight > ...

Having trouble accessing the text in a paragraph using JavaScript executor and web driver

On a particular website, there is: <p id="tempid" value="Manual Effect">testing the test</p> String value = (String)((JavascriptExecutor) this).executeScript("return window.document.getElementById('tempid').value"); System.out.pr ...

Change the Background of Your Body?

Here's the deal. I'm looking to create a cool effect where the background of the body slowly fades out and changes periodically in a loop using CSS and jQuery. Any suggestions on how I can make this happen? Appreciate your help! ...

Utilizing Moment.js: Transforming 12-hour format to a Date object

Is there a way to convert a 12-hour string into a 24-hour Date object? day.from = day.from || moment("6:00", ["h:mm"]).format("HH:mm"); Unfortunately, I am encountering the following error: angular.js:11706 Error: [ngModel:datefmt] Expected `6:00` to be ...

What are some strategies to prevent django form fields from being reset or cleared in the event of an error during submission?

I'm utilizing django's registration-redux for user registration, but I'm facing an issue. When I enter the same user ID, it displays an error and clears all the input fields on the form. How can I prevent this error from occurring without cl ...

How can I retrieve the updated input value once a specific key has been pressed in the prototype?

After a customer presses any key, I would like to check an email. Below is the code I am using: document.observe("dom:loaded", function() { $('billing:email').observe('keypress', function(event){ console.log(event.element(). ...

Can a before hook ever run after a test in any situation, Mocha?

My before hook runs after the initial test and at the conclusion of the second test. Here is the code for my before hook: before(function () { insightFacade.addDataset("courses", content) .then(function (result: InsightResponse) { ...

Switch up div containers with JavaScript based on the set array order of elements?

As I work on creating a list that calculates the sum of selected numbers, I encountered an issue with rearranging the items. Despite successful functionalities like adding images with names, changing languages, and performing calculations, the page keeps r ...

JavaScript interval setting multiples

In my current situation, I have implemented a setInterval based code that continuously checks the value of an AJAX call response. Here is how it looks: var processInterval = setInterval(function () { var processResult = getVideoStatus(data.file_name) ...

Trouble with setting the scope input value

HTML <input type="text" ng-model="connector_form.a" class="form-control col-md-7 col-xs-12" placeholder="{productname}"> Controller: $scope.connector_form.a = "test"; Not functioning as expected. When I modify it to: HTML <input type="te ...

Stopping the animation of scrollLeft upon user interaction can be achieved by utilizing JavaScript

Here is my current code snippet: <script> $(document).ready(function() { $('.scrolls').stop().animate({ scrollLeft : 4000 },100000, 'linear') }) </script> I am looking for a way to halt the animation once ...