Two way binding, scope variable undefined

2019-07-28 15:03发布

I'm writing an app with OnesnUI and AngularJS, using ng-model to get the input from DOM elements.

There's my code

<body>
  <ons-screen>
      <ons-page class="center" ng-controller="page1Ctrl">
    <ons-navigator title="Page 1">
        <div class="center">
          <h1>Pharmy</h1>
            <ons-text-input ng-model="medName" placeholder="Enter Medicine Name" style="display:block; width:100%;" id="test"></ons-text-input>
            <div style="position:relative">
                <ons-text-input ng-model="location" placeholder="Enter Location" style="display:block; width:100%; margin-top:10px;"></ons-text-input>
                <ons-icon icon="search" style="position:absolute;right:10px;top:5px;"></ons-icon>
            </div>
            <ons-button ng-click="goToPage2()"
                        style="width:10%; margin-top:10px;">
                <ons-icon icon="search"></ons-icon>
            </ons-button>
        </div>
    </ons-navigator>
          </ons-page>
  </ons-screen>
</body>

and trying to retrieve the value from input textbox, there's my app.js:

    (function () {
        'use strict';
        var app = angular.module('myApp', ['onsen.directives']);
        app.controller('page1Ctrl',['$scope','pageService',function($scope,pageService){
            $scope.$watch('medName',function(newVlaue){
                console.log('Watching YOU !' + newVlaue);
            });
            console.log($scope.medName);
            $scope.goToPage2 = function(){
                console.log('Going to page2 !');
                console.log($scope.medName);
                pageService.start($scope.medName);
                $scope.ons.navigator.pushPage("page2.html");
            }
        }]);
    })();

Why is the medName printed value undefined ?

4条回答
Lonely孤独者°
2楼-- · 2019-07-28 15:31

Created a simple jsfiddle to show how it is being done and working well in Angular.

The first console.log of yours will be undefined as you have not set anything in the controller

Something like

 $scope.medName = '';

would have helped.

Code Snippet of the controller that I used in the example to demonstrate:

function test($scope){
    $scope.medName = '';
    console.log($scope.medName);
    $scope.$watch('medName',function(newValue){
        console.log("new Value:"+newValue);
    });
    $scope.getUpdatedScope = function(){
        console.log($scope.medName);
    }
}
查看更多
兄弟一词,经得起流年.
3楼-- · 2019-07-28 15:31

Are you setting the ng-app directive somewhere? Try adding it to the body tag, like this:

<body ng-app="myApp">
查看更多
别忘想泡老子
4楼-- · 2019-07-28 15:45

You code actually works, did you type something in the actual input? It writes undefined at the beginning because it is, it's not defined in the scope, and your input value is null.

I made a jsfiddle quickly, here is the (basically your) code. HTML:

<div ng-app="myApp">
    <div ng-controller="page1Ctrl">
        <input ng-model="medName" />
        <p ng-if="medName">{{medName}}</p>
    </div>
</div>

JS:

var app = angular.module('myApp', []);
app.controller('page1Ctrl',['$scope', function($scope){
    $scope.$watch('medName',function(newVlaue){
        console.log('Watching YOU !' + newVlaue);
    });
    console.log($scope.medName);
}]);

Here is the jsfiddle: http://jsfiddle.net/q3z22/4/ You'll see in the console "undefined" at the beginning, and then whatever you write in the input. If you don't want that, just define in the scope by writing $scope.medName = ''; and you'll have an empty string at the start.

查看更多
神经病院院长
5楼-- · 2019-07-28 15:56

If I have to name a proper pain in Angular, it would be scope inheritance.

If you have let's say $scope.foo = "hello" is the controller and then you create a children scope of that controller and then you try to assign a new value to foo that would crete a new foo inside that new scope. Your parent controller will never see the changes.

In your problem, you are not creating a new scope, but that OnsenUI is doing so maybe on the ons-screen or ons-navigator. Then your input is inside a new child scope and if you try to assign the newMed it is going to do so on the child scope.

The rule always is to have objects, that is called the dot rule (check here).

So if you don't want to have this problem again, always do like I told you on the comment, create something like $scope.meds = {} and then ng-model="meds.newMed" because that way, it will search for meds on the parents first and if it finds it, it will use it and that is what you want to do.

Here is the first example of doing it wrong: http://plnkr.co/edit/IJZOa1pXtcQePiEVMzjZ?p=preview

<body ng-controller="MainCtrl">
  <foo>
    <input ng-model="name"> <br />
    Inside new scope: {{ name }}
  </foo>
  <br />
  On the parent scope: {{ name }}

app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
});

app.directive('foo', function() {
  return {
    restrict: 'E',
    scope: true
  };
});

Here we are a directive that is creating a new scope called foo. Then on our html, inside <foo> we put a ng-model with name. It reads the current scope, oh, not there, so it goes up to the controller's scope and find it. So you see World on the input. When you change the input, it will grab the content of it and assign a new value. How? It goes to its scope, and assign it. The problem is that its scope is the new scope created by foo and because of that, the parent will never see any changes.

Let's see example number two: http://plnkr.co/edit/BSx37PpAEbPnHfs2jr5o?p=preview

<body ng-controller="MainCtrl">
  <foo>
    <input ng-model="user.name"> <br />
    Inside new scope: {{ user.name }}
  </foo>
  <br />
  On the parent scope: {{ user.name }}
</body>

-

app.controller('MainCtrl', function($scope) {
  $scope.user = {
    name: 'World'
  };
});

app.directive('foo', function() {
  return {
    restrict: 'E',
    scope: true
  };
});

Here, same example but with a minor change. Here we have name inside an object called user. When the input reads it, there is no difference but when it is going to asign a new value, it does something different, something like: Hey new scope, do you have this user object? Errr no... ok, parent, you have this user object? I do. Good, then put into it a property called name with this content.

Do you see the difference? Before it didn't ask it parent, it just created the name on the inner scope, but if you use objects, it will try to find the object first, exactly what we need.

The TL;DR; is: always use objects because what happened to you is that some of the directives you were using are creating new scopes and your new assignments are going to be created on inner scope.

查看更多
登录 后发表回答