2

I have this index.html which has a navbar in the which is seen on all pages of my single page application. The navbars container div is using the ng-controller="LoginCtrl" value, so I will also include that controller from my angular application (app.js)

For some reason, the variables username and password which are bound via ng-model are showing as undefined when doLogin() is called via ng-click directive? That is after I type values into the text boxes that are bound to my controllers variables.

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="LoginCtrl">
        <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 ng-if="!loggedIn" id="loginForm" class="navbar-form navbar-right">
                        <div class="form-group">
                            <input type="text" placeholder="Email" class="form-control" ng-model="username">
                        </div>
                        <div class="form-group">
                            <input type="text" placeholder="Password" class="form-control" ng-model="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 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>

app.js

...
myApp.controller('LoginCtrl', function($rootScope, $location, AuthService, AuthToken) {

    $rootScope.doLogin = function() {
        console.log($rootScope.username);
        console.log($rootScope.password);
    }

});
...
e-shfiyut
  • 3,538
  • 2
  • 30
  • 31
JohnWick
  • 4,929
  • 9
  • 37
  • 74
  • Use `$scope` rather than `$rootScope`. We should have to make our `$rootScope` as thinner as possible for an app. – Vineet Sep 16 '15 at 05:23
  • Hi, $scope does not work either, both say undefined. – JohnWick Sep 16 '15 at 05:31
  • Share more code or create a fiddle. I can not see your module declaration – Vineet Sep 16 '15 at 05:35
  • Here is my module declaration var myApp = angular.module('myApp',['ngRoute', 'ngStorage']); – JohnWick Sep 16 '15 at 05:36
  • Does this answer your question? [Ng-model does not update controller value](https://stackoverflow.com/questions/12618342/ng-model-does-not-update-controller-value) – ofthelit Dec 11 '19 at 10:12

4 Answers4

2

An inputModel primitive property will be created on that ng-controller's scope when you type into the text field. input model is generated in the current scope, not the rootScope.

var app = angular.module('myApp', []);
app.controller('LoginCtrl', function($scope, $http) {
  $scope.doLogin = function() {
        console.log($scope.username);
        console.log($scope.password);
    }
});

Check it out on Plunker

Kamran Ahmed
  • 7,661
  • 4
  • 30
  • 55
kavinhuh
  • 739
  • 1
  • 9
  • 30
  • injecting $scope into LoginCtrl was what I was originally trying to do, but it wasn't working so I just tried $rootScope – JohnWick Sep 16 '15 at 05:32
  • I have updated my code back to using $scope as you are showing, and it is not working. – JohnWick Sep 16 '15 at 05:41
  • Nope, just sharing $scope.username and $scope.password are undefined in the console.log output. Even though they are bound to $scope variable via ng-model="username" on a textbox in index.html – JohnWick Sep 16 '15 at 06:50
  • @DavidStampher please check now – kavinhuh Sep 16 '15 at 07:28
  • Check the answer I posted below, I added parameters to doLogin(user, pass), and called doLogin in my ng-click button like this doLogin(user.name, user.pass) and it works. – JohnWick Sep 16 '15 at 07:47
1

Use model rather than using primitive types.

You should use $rootScope.user.name (ng-model will be user.name) rather than using $rootScope.username and $rootScope.user.password(ng-model will be user.password) instead of $rootScope.password

This problem actually happens for javascript's prototypical model. And if you want to know it's applicability in angularjs, you can go through this article. This will definitely help :)

Edit: As you are running into problem making that code work, I've made a working copy of your code. Please have a look at it:

<!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="LoginCtrl">
        <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 ng-if="!loggedIn" id="loginForm" class="navbar-form navbar-right">
                        <div class="form-group">
                            <input type="text" placeholder="Email" class="form-control" ng-model="user.name">
                        </div>
                        <div class="form-group">
                            <input type="text" placeholder="Password" class="form-control" ng-model="user.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 ng-view></div>
    </div>

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

</body>
</html>

<script>
    var myApp = angular.module("myApp", []);
    myApp.controller('LoginCtrl', function ($scope, $location) {

        $scope.user = { name: "", password: "" };
        $scope.doLogin = function () {
            console.log($scope.user.name);
            console.log($scope.user.password);
        }

    });
</script>
Md Hasan Ibrahim
  • 1,868
  • 19
  • 27
  • Hi, I changed ng-model in index.html to ng-model="user.name" and in my LoginCtrl's doLogin function to this: console.log($rootScope.user.name); and it says cannot read property 'name' of undefined? – JohnWick Sep 16 '15 at 05:30
  • You need to initialize the object first. May be with an empty object. like $rootScope.user ={name:"",password:""}; – Md Hasan Ibrahim Sep 16 '15 at 05:32
  • I have just done this, and it made the exception I mentioned go away, but the variables are not being updated when I type text into the input boxes, according to console.log which is called in doLogin – JohnWick Sep 16 '15 at 05:34
  • So it is showing $rootScope.user.name is an empty string, as it was initialized too, even though it should have been updated by ng-model – JohnWick Sep 16 '15 at 05:35
  • I've edited my answer for your convenience. Please have a look – Md Hasan Ibrahim Sep 16 '15 at 05:54
  • Hi, I've updated my code and console.log shows that $scope.user.name and $scope.user.password are both empty strings when doLogin is called, even though I am entering text into the textboxes that are bound via ng-model – JohnWick Sep 16 '15 at 06:49
1

use $scope instead of $rootScope for getting the ng-model in controller.

e-shfiyut
  • 3,538
  • 2
  • 30
  • 31
nidhin
  • 419
  • 1
  • 4
  • 16
  • I have injected $scope into LoginCtrl, created an empty JSON object called user with properties name and pass, attached that to $scope, and updated my ng-models to user.name and user.pass, and console.log is showing user.name and user.pass as empty strings, even though they should have had their values updated due to ng-model? – JohnWick Sep 16 '15 at 05:39
  • app.controller('LoginCtrl', function($scope, $http) { $scope.doLogin = function() { console.log($scope.username); console.log($scope.password); } }); – nidhin Sep 16 '15 at 05:49
1

I found the answer to my own question after some frustration. Adding username and password arguments to my doLogin() function, then using the directive ng-click="doLogin(user.name, user.pass)" works as I wanted. No clue why it wasn't working the way I was trying, but oh well.

e-shfiyut
  • 3,538
  • 2
  • 30
  • 31
JohnWick
  • 4,929
  • 9
  • 37
  • 74
  • **Very frustrating...** I've spent the last 2 hours trying to figure out why exactly the same issue is happening to me while I was developing a new module for my main app. Just tried doing what you suggested and it works.. Inside my app, I have other functions which manipulate models without specifying them as arguments and work flawless. _Can you mark your answer as accepted or the main one? I think it could help others in our exact situation_ – Dincă Alexandru Oct 20 '15 at 22:27
  • @DincăAlexandru Hey I marked it, but I was somehow able to get it to work without having to supply my variables as arguments to doLogin(). But, this also did solve my original issue for whatever reason. – JohnWick Oct 21 '15 at 23:20
  • Hey @David, I guess you can't explain that *somehow*? I'm still curious why I wasted those hours on something as trivial as this. – Dincă Alexandru Oct 22 '15 at 08:13
  • See https://stackoverflow.com/a/22768720/1885735 String is a primitive. When Angular assigns the value it changes the pointer to the value. So when the controller looks at the old value it has the old pointer to the value. – ofthelit Dec 11 '19 at 10:10