Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

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!');
share|improve this question
    
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. – user2341963 Sep 7 '15 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 :) – David Stampher Sep 7 '15 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. – user2341963 Sep 7 '15 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. – David Stampher Sep 7 '15 at 5:56

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.

share|improve this answer
    
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. – David Stampher Sep 7 '15 at 5:47
    
@DavidStampher updated! – Medet Tleukabiluly Sep 7 '15 at 5:58
    
Hi, the routeProvider is in the example already :P / and /home are routed to different views but the same controller. – David Stampher Sep 7 '15 at 6:03

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.

share|improve this answer
    
Hey Cody I'll play around with this a bit and see if it makes things work the way I want them too. – David Stampher Sep 7 '15 at 12:59
    
sure @DavidStampher please consider accepting it :P :P – NavyCody Sep 8 '15 at 6:01

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.