I have got a form where user will enter a name and click Next. What I want to do is that, when the user clicks Next, I want to alert the updated value of $scope.name inside toChat function, but initial value is alerted, which is James. How can I access the updated value inside angular function? I have some serious problems understanding sharing variables within AngularJs.
js
.controller('NewcontactCtrl', function($scope,$rootScope, $ionicHistory,$window) {
$scope.name='James';
$scope.myGoBack = function() {
$ionicHistory.goBack();
};
$scope.toChat = function() {
alert($scope.name);
};
})
html
<ion-view view-title="New contact">
<ion-nav-back-button>
</ion-nav-back-button>
<ion-nav-buttons side="primary">
<button class="button" ng-click="myGoBack()">
Cancel
</button>
</ion-nav-buttons>
<ion-nav-buttons side="secondary">
<button class="button" ng-click="toChat()" >
Next
</button>
</ion-nav-buttons>
<ion-content scroll="false" has-header="false" padding="true" >
<div class="list">
<label class="item item-input">
<input type="text" placeholder="Name" ng-model="name" />
</label>
<label class="item item-input">
<textarea placeholder="Notes" ng-model="notes" rows="10"></textarea>
</label>
</div>
</ion-content>
</ion-view>
Can anyone help ?
Please see: https://github.com/angular/angular.js/wiki/Understanding-Scopes
The most relevant part in the above:
Scope inheritance is normally straightforward, and you often don't even need to know it is happening... until you try 2-way data binding (i.e., form elements, ng-model) to a primitive (e.g., number, string, boolean) defined on the parent scope from inside the child scope. It doesn't work the way most people expect it should work. What happens is that the child scope gets its own property that hides/shadows the parent property of the same name. This is not something AngularJS is doing – this is how JavaScript prototypal inheritance works. New AngularJS developers often do not realize that ng-repeat, ng-switch, ng-view and ng-include all create new child scopes, so the problem often shows up when these directives are involved. ...
This issue with primitives can be easily avoided by following the "best practice" of always have a '.' in your ng-models – watch 3 minutes worth. Misko demonstrates the primitive binding issue with ng-switch.
Having a '.' in your models will ensure that prototypal inheritance is in play. So, use
<input type="text" ng-model="someObj.prop1"> rather than
<input type="text" ng-model="prop1">.
I believe you have a directive in there somewhere (probably ion-content) that is creating a new scope where your input field is, separated from the scope where your Next button is.
To simulate this, I've used ng-repeat in the below snippet (but I'm repeating only once), which causes the same behaviour of splitting the scopes. If you were to use your controller code unmodified with this html, you'd reproduce the issue you're experiencing.
The solution around this is to 'use a dot (.)' when binding. Notice that I've wrapped the name within an object called 'data' on the scope, so now you refer to this as data.name instead of just name.
(function() {
'use strict';
angular.module('myApp', [])
.controller('NewcontactCtrl', function($scope, $window) {
$scope.repeaterTest = [1];
$scope.data = {name: 'James'};
$scope.toChat = function() {
$window.alert($scope.data.name);
};
});
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="NewcontactCtrl">
<label ng-repeat="test in repeaterTest">
<input type="text" placeholder="Name" ng-model="data.name" />
</label>
<button class="button" ng-click="toChat()">
Next
</button>
</div>
</div>
I think you need to alert something similar to...
alert($scope.name)
Addition to #Paul Fitzgerald, points, ensure that ng-controller="NewcontactCtrl" is included at the top scope in HTML DOM.
try adding a service in order to share data within scopes
.controller('NewcontactCtrl', function($scope,$rootScope,sharedData $ionicHistory,$window) {
$scope.name=sharedData.Name ;
$scope.myGoBack = function() {
$ionicHistory.goBack();
};
$scope.toChat = function() {
alert(sharedData.Name);
};
});
app.factory('sharedData', [function () {
var self = {};
self.Name = "James";
return self;
}]);
Related
My ng-model is value not updating in controller bonded with $scope. There is no syntax error in my code that I can assure. Only one controller bonded with html.
$watch is only running once when page is loaded.
Note that I have 220 around total watchers in my file and controller file is very big like 1500+ lines of code. To cross check I also bind one div with different controller and it is working as expected both $watch and $scope.
I have verified that my variable is not having duplicate name in entire project. I think angular gives no performance issue till 2000 watchers per page. But here that is not the case. Can someone please shed some light on this strange behavior. Any help would be appreciated.
Note: I am not posting code here as it was working fine when I started working on controller initially and on separate prototype also code works well. This behavior has been introduced recently with more and more code.
HTML file:
<div id="studentSearch" class="form-group__text row studentmargin">
<input id="search" type="text" class="studentSearch" tabindex="2"
ng-keyup="$event.which === 13 && !disableSearch ? clickSearchButton(): ''"
placeholder="Search by Name or Email"
ng-model="searchString">
<label for="search">
<button type="button" class="link" tabindex="3"
ng-click="clickSearchButton()" ng-if="!searchResultFlag"
ng-disabled="disableSearch">
<span class="icon-search"></span>
</button>
</label>
<button type="button" class="link" ng-click="clearStudentsSearch()"
ng-if="searchResultFlag" tabindex="4">
<span class="icon-close"></span>
</button>
Controller:
angular.module('app.pages.course.details').controller("CourseDetailController", ['$scope', function($scope){
$scope.disableSearch = true;
$scope.$watch('searchString', function(oldValue, newValue){
if(newValue.length >= 3) {
$scope.disableSearch = false;
}
});
$scope.clickSearchButton = function() { /* Search logic */ }
$scope.clearStudentsSearch = function() {
$scope.searchString = "";
} }]);
So the logic is search icon will only get enabled once the searchString is greater than or equal to 3 letters. On clearing search button it gets cleared from UI and if we print the scope it has that value, Because of that on ENTER press, search work again.
Could you try using parent with the model ng-model="parent.name".
Can I use ng-model to build up an object over several views?
For instance, say in view1 I have
<input ng-model='myObject.firstName'>
And in view2 I have
<input ng-model='myObject.lastName'>
And in view3 I have
<input ng-model='myObject.email'>
The idea being you could hit a submit button in the last view, and return the object somewhere.
My initial approach to this is to have a service which declares an empty object, then have functions in the service which allow the controllers using the service to add their view input to that object, then return the object.
However I feel like this is quite a roundabout way of doing it!
If anyone could point me in the right direction I would really appreciate it.
You can use a service for that. Here an example with 3 controllers sharing the same object using 3 directives ng-model. Each controller modify the tested.value property, but you can use differents properties of course.
angular.module('test', []).factory('tested', function() {
return {
value : '123'
};
}).controller('ctrl1', function($scope, tested) {
$scope.tested = tested;
}).controller('ctrl2', function($scope, tested) {
$scope.tested = tested;
}).controller('ctrl3', function($scope, tested) {
$scope.tested = tested;
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test">
<div ng-controller="ctrl1">
<input type="text" ng-model="tested.value" />
{{ tested.value }}
</div>
<div ng-controller="ctrl2">
<input type="text" ng-model="tested.value" />
{{ tested.value }}
</div>
<div ng-controller="ctrl3">
<input type="text" ng-model="tested.value" />
{{ tested.value }}
</div>
</div>
Since each view has its controller, the only way to share data is with a service of type "provider", "service" or "factory".
You could then modify your object from each controller with the methods you talk about.
In the end, to notify each view something changed, the service methods could raise an event from the service :
$rootScope.$broadcast('somethingChanged', myObject);
And each controller could listen with:
$scope.$on('somethingChanged', function(data) {
});
I was using ng-include on a few of my pages, however I had to stop using ng-include because it was breaking the angular-ui datepicker. I opened this Github bug.
I am wondering if anyone else was having issues with directives not functioning the same way when being used as part of a ng-include.
Is there a way to make the datepicker work as expected as part of a ng-include?
Here is a plunker showing how it is broken. http://plnkr.co/edit/AboEJGxAK3Uz76CfpaZ0?p=preview
Here is the html that works when on the view, but does not work when part of a ng include.
<div class="row">
<div class="col-md-2">
<p class="input-group">
<input type="text" class="form-control" datepicker-popup="yyyy/MM/dd" ng-model="something.dt2" is-open="secondCal"
min-date="minDate" name="secondCal" max-date="'2015-06-22'" datepicker-options="dateOptions"
date-disabled="disabled(date, mode)" ng-required="true" close-text="Close"/>
<span class="input-group-btn">
<button type="button" class="btn btn-default" style="line-height: 1.2em" ng-click="open($event, 'secondCal')">
<i class="ss-icon ss-calendar"></i>
</button>
</span>
</p>
</div>
</div>
Here is the JS from the controller.
$scope.open = function ($event, elementOpened) {
$event.preventDefault();
$event.stopPropagation();
$scope[elementOpened] = !$scope[elementOpened];
};
And two ways I was doing ng-include
<div ng-include src="'dist/partials/myPartial.html'"></div>
<div ng-include="'dist/partials/myPartial.html'"></div>
Update
I found that this is because the ng-include directive creates a new scope for each include. This SO post creates a new directive that does the include without creating a new scope. However there seems there "should" be a way to fix it without using a different include.
The datepicker will be unable to open as soon as the is-open is changed by the datepicker directive itself (e.g. click outside to close the datepicker).
This is a common issue regarding the "Prototypal Inheritance" characteristic of scope.
For a complete detail, you could read this: Understanding-Scopes
You could easily solve this by not storing any primitive values directly into $scope, but some object and using dot-notation like this:
<input type="text" class="form-control"
datepicker-popup="yyyy/MM/dd" ng-model="something.dt2"
is-open="model.secondCal"
and in your controller:
app.controller('MainCtrl', function($scope) {
$scope.model = {};
$scope.open = function($event, elementOpened) {
$event.preventDefault();
$event.stopPropagation();
$scope.model[elementOpened] = !$scope.model[elementOpened];
};
});
Example Plunker: http://plnkr.co/edit/dJNIwSz2Uot3McmIMhd4?p=preview
I've created Plunker to debug it but it works fine with your code
http://plnkr.co/edit/nxYCiwRqdWMOkfZoRhGY?p=preview
<body ng-controller="MainCtrl">
<div ng-include="'partial.html'"></div>
</body>
after clarification and further tests i see that calendar with ng-include lose the scope when triggering the change not by scope method, the easy workaround would be as per this plunker
http://plnkr.co/edit/nxYCiwRqdWMOkfZoRhGY?p=preview
Don't remember which one of the angular team said it but if you don't have a dot in your model you are doing it wrong.
a little explanation why it works:
if you do
$scope.valueName = value
it will assign value to the current scope immediately
but if you do
$scope.something.valueName = value
what will happen is that angular will first locate $scope.something, if it doesn't exists on current scope it will look in parent (as long as you don't work in isolated scope)
then when it finds it it will assign value or return something like 'cant find valueName of undefined'
from the angularjs documentation:
https://docs.angularjs.org/api/ng/directive/ngInclude
This directive creates new scope.
This directive executes at priority level 400.
I'm trying to get started learning AngularJS for an Ionic app I'm working on, and I'm having a little trouble understanding AngularJS having had most previous experience on jQuery which focuses on DOM manipulation rather than frameworking.
If I have the following markup:
<label class="item-input-wrapper">
<i class="icon ion-ios7-chatbubble placeholder-icon"></i>
<input type="text" placeholder="Send a message...">
</label>
<button class="button button-clear button-positive">
Send
</button>
How can I pass the value of the input on to the controller when enter or send is clicked? I'm working on a chat app, so I believe that a model approach is needed so that the message thread can be automatically updated but other than that I have no idea.
Could someone help me out or at least point me in the right direction?
There are several ways to pass value to your controller. Here is the simplest example. As Justin said, you should look into angular basics.
HTML:
<div ng-controller="MyCtrl">
<input type="text" ng-model="foo" placeholder="Enter something" />
<input type="button" ng-click="doSomething()" value="Send" ng-disabled="foo == null" />
</div>
JS:
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.foo = null;
$scope.doSomething = function () {
alert("Hello, " + $scope.foo);
}
}
Here is the working fiddle
And I would recommend you to go through this post.
The following markup you posted is the view. What you'll need to do is write a separate JS script called a controller that gets linked to the view. Look into basic Angular tutorials on how to do that and mainly look into how $scope works in Angular.
Your controller will have a function...say:
$scope.foo = function(input) { alert(input); };
From the view, you can pass a value onto the controller with Angular functions such as ng-click.
<a ng-click="foo('this string will be passed in as the text of the alert')">click me</a>
I'm actually not sure what the title of the question should be, as it's not clear to me what I am missing.
I have boiled this down to a very simple example (the actual case is more complex). I have a text box and button inside of an ng-switch. The switch, I've read, creates it's own local scope.
What I want to do pass the value of the text box to a function when the button is clicked. In the function, I will do what needs to be done with the value, then clear the text box. I'm struggling to find the right way to do this.
Controller Code:
$scope.temp = 1;
$scope.tempCall = function (tempModel) {
tempModel = ""; //this doesn't work
$scope.tempModel = ""; //nor does this
};
HTML/Template:
<div ng-switch on="temp">
<div ng-switch-when="1">
<input ng-model="tempModel" />
<input type="button" ng-click="tempCall(tempModel)" />
</div>
<div ng-switch-when="2">TWO</div>
</div>
I believe I can actually traverse the scope from the parent or root scope and clear the value, but that doesn't "feel" correct. What is the correct (Angular) way to clear this value?
When you are working with primitive values in angular scopes, you cannot overwrite a value in a parent scope from a child scope. This is because angular uses javascript prototypal inheritance.
What you could do in this case is create an object in the parent scope, then you can update the values on that in the child scope. Because you are not overwriting the object (only properties attached to it) the references work.
I created a demo of this on plunk you can view it here
$scope.temp = 1;
$scope.tempModel = {};
$scope.tempCall = function () {
$scope.tempModel.previous = $scope.tempModel.value
$scope.tempModel.value = "";
};
<div ng-switch on="temp">
<div ng-switch-when="1">
<input ng-model="tempModel.value" />
<input type="button" ng-click="tempCall()" />
{{tempModel.previous}}
</div>
<div ng-switch-when="2">TWO</div>
Here's one way to do it:
<input type="button" ng-click="tempCall(tempModel);tempModel='';" />
Probably the more "Angular way" would be to use a dot in your model like:
<input type="text" ng-model="tempModel.value" />
Then call your function by passing the tempModel object like:
<input type="button" ng-click="tempCall(tempModel)" />
Then you will be able to clear the value with:
$scope.tempCall = function (tempModel) {
tempModel.value = "";
};
Here is a fiddle
To prevent databinding issues, "the rule of thumb is, if you use ng-model there has to be a dot somewhere." Miško Hevery