2

basically my issue is that I have a AngularJS view (home.html) which contains a variable in double brackets like so: {{message}}

When the $scope.message variable is modified, the view with does not update, although it should? I have tried adding $scope.$apply() which results in an exception along the lines of 'Action in Progress'

Check my code below. The {{message}} part in home.html is not being updated when $scope.doLogin is called in MainCtrl, even though I have set $scope.message to a new value in that function.

Any help is greatly appreciated and if any further info is needed, please ask.

index.html

<!DOCTYPE html>

<html ng-app="myApp">
<head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
    <link href="stylesheet.css" rel="stylesheet">

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.4/angular.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.4/angular-route.min.js"></script>
    <base href="/">

    <script src="https://cdnjs.cloudflare.com/ajax/libs/ngStorage/0.3.9/ngStorage.js"></script>
    <script src="https://cdn.socket.io/socket.io-1.3.5.js"></script>

</head>
<body>

    <div ng-controller="MainCtrl">
        <nav class="navbar navbar-default">
            <div class="container">
                <div class="navbar-header">
                    <a class="navbar-brand" href="#">TriviaAttack</a>
                </div>
                <div id="navbar" class="navbar-collapse collapse">
                    <form id="loginForm" class="navbar-form navbar-right">
                        <div class="form-group">
                            <input type="text" placeholder="Email" class="form-control" ng-model="loginData.username">
                        </div>
                        <div class="form-group">
                            <input type="text" placeholder="Password" class="form-control" ng-model="loginData.password">
                        </div>
                        <div class="form-group">
                            <button type="submit" class="btn btn-success" ng-click="doLogin()">Sign In</button>
                        </div>                  
                    </form>
                </div>
            </div>
        </nav>
    </div>

    <div ng-view>

    </div>
    </div>

    <script src="./app/app.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js">

</body>
</html>

home.html

<div>
    <h1>Welcome to the Home Page</h1>
    <p>{{message}}</p>
</div>

app.js

var myApp = angular.module('myApp',['ngRoute', 'ngStorage']);

myApp.controller('MainCtrl', ['$rootScope', '$scope', '$location', 
    function($rootScope, $scope, $location) {

    $scope.message = 'testing message';

    $scope.loginData = {
        username: '',
        password: '',
        loggedIn: false
    }

    $scope.doLogin = function() {

        $scope.message = 'message changed!';
        $scope.$apply();

        Auth.doLogin($scope.loginData.username, $scope.loginData.password)
        .success(function(data) {
            if (data.success) {
                AuthToken.setToken(data.token);
                $location.path('/home');
                console.log($scope.loginData.loggedIn);
            }
        });

        $scope.loginData = {};
    }

}]);

//Middleware for all requests which adds the users token to the HTTP header.
myApp.factory('TokenInterceptor', ['$q', '$location', '$localStorage',
    function($q, $location, $localStorage) {

    //On each request, check if the user is logged in with a valid token.
    var interceptor = {
        request: function(config) {

            config.headers['X-Authorization-Token'] = $localStorage.token;
            return config;

        },
        responseError: function(response) {
            if(response.status === 401 || response.status === 403) {
                $location.path('/login');
            }
            return $q.reject(response);
        }
    };
    return interceptor;
}]);

myApp.config(['$routeProvider','$locationProvider','$httpProvider',
    function($routeProvider, $locationProvider, $httpProvider) {

        $routeProvider.
            when('/', {
                templateUrl: './app/views/landingpage.html',
                controller: 'MainCtrl'
            }).
            when('/home', {
                templateUrl: './app/views/home.html',
                controller: 'MainCtrl'
            }).
            otherwise({
                redirectTo: '/'
            });


        $locationProvider.html5Mode(true);

        $httpProvider.interceptors.push('TokenInterceptor');

    }

]);

console.log('app.js loaded!');
4
  • All your views are using their own MainCtrl and have their own $scope so when you call doLogin from the the login form it will only update the message in it's own scope, not the controller of the ng-view. Commented Sep 7, 2015 at 5:35
  • Hi, so what I am trying to do is not possible? Or what is your suggested solution. I appreciate your response btw thank you :) Commented Sep 7, 2015 at 5:49
  • See Angular: Share data between controllers. In a nutshell, return an object from a factory and work off that in the controllers. Let us know if it doesn't help. Commented Sep 7, 2015 at 5:55
  • Thanks for the link. I will change my code a bit and implement the pattern and let you know if it works. Commented Sep 7, 2015 at 5:56

2 Answers 2

2

Each time a view is loaded ,the controller code with new scope executes so the new message is not reflected. So the flow be like landingPage's controller which is MainCtrl with its scope when $scope.doLogin is executed will change the $scope.message variable to "Message Changed" and upon changing location to home , the MainCtrl is assigned to home page with new scope which would continue executing the very first line of MainCtrl i.e.

  $scope.message = 'testing message';

As you have decided to use common controller for login and home pages

Try removing controller option in

when('/', {
  templateUrl: './app/views/landingpage.html',
  controller: 'MainCtrl'
}).
when('/home', {
  templateUrl: './app/views/home.html',
  controller: 'MainCtrl'
}) 

And assign controller in

<div ng-controller="MainCtrl">
    <!--omitted-->
    <div ng-view></div>
</div>

Or else other options would be to pass parameters or use ui-router wherein nested views would automatically inherit from parent controllers without rerunning the controller logic.

Sign up to request clarification or add additional context in comments.

2 Comments

Hey Cody I'll play around with this a bit and see if it makes things work the way I want them too.
sure @DavidStampher please consider accepting it :P :P
1

Problem is in controller coverage

<div ng-controller="MainCtrl">
    <!--omitted-->
</div>
<div ng-view></div>

Your $scope.message is tight to your MainCtrl, so when ng-view is populated, you except that it has MainCtrl, but indeed it's outside of that div, so just doesn't see that variable, to make it work, insert ng-view to MainCtrl div like shown below

<div ng-controller="MainCtrl">
    <!--omitted-->
    <div ng-view></div>
</div>

But here's the actual problem

You tend to use ng-route but you don't have any route configurations, ng-view will never be populated with home.html unless you configure you routeProvider, first of all, make some routes like described here, perform your form action, redirect to page and populate views accordingly, it should work.

2 Comments

Hi, I made the change and called doLogin() via ng-click (which changes $scope.message), but {{message}} in home.html still did not update. Even with the ng-view div nested inside as you advised.
Hi, the routeProvider is in the example already :P / and /home are routed to different views but the same controller.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.