Angular: update scope inside scope - javascript

I have a controller with 2 scopes:
app.controller('search', function($scope) {
$scope.value1 = '';
$scope.value2 = 'Some text' + $scope.value1;
}
And an input field:
<input type="text" ng-model="value1">
When I change value1 with the input field (which works), value2 doesn't get updated. How can I make this work?

You could follow dot rule while declaring object. That will give you prototypal inheritance thing. Both param1 & param2 will refer to the same copy of object. So that updating one would update the other one automatically.
Markup
<input type="text" ng-model="param1.value">
<input type="text" ng-model="param2.value">
Controller
app.controller('search', function($scope) {
$scope.param1 = {value : ''};
$scope.param2 = $scope.param1;
}
Demo Plunkr
Update
If you wanted to keep those variable as primitive then you should have to update them on some event like here you could do it by using ng-change directive
Markup
<input type="text" ng-model="value1" ng-change="value2 = value1 + ' something'">
Or simply you can move inline html code to you controller function to make it testable.
Markup
<input type="text" ng-model="value1" ng-change="changedValue()">
Code
$scope.changedValue = function(){
$scope.value2 = $scope.value1 + ' something'
}

Related

How to retrieve the value from textbox using AngularJs?

$scope.add=function()
{
//How to retrieve the value of textbox
}
<input type='text'><button ng-click='add()'></button>
When I click on the button, how can I retrieve the textbox value in the controller and add that value to the table dynamically?
Assign ng-model to it so that variable will be available inside scope of controller.
Markup
<input type='text' ng-model="myVar"/>
<button type="button" ng-click='add(myVar)'></button>
Bind the text field using ng-model
Example:
$scope.items = [];
$scope.newItem = {
title: ''
}
$scope.add = function(item) {
$scope.items.push(item);
$scope.newItem = { title: '' }; // set newItem to a new object to lose the reference
}
<input type='text' ng-model='newItem.title'><button ng-click='add(newItem)'>Add</button>
<ul>
<li ng-repeat='item in items'>{{ item.title }}</li>
</ul>
To take your data from textbox, you should use ng-model attribute on the HTML element. On the button element you can use ng-click with a parameter which is your ng-model
Example:
Your HTML:
<input type='text' ng-model="YourTextData"/>
<button type="button" ng-click='add(YourTextData)'></button>
Your Js:
$scope.add=function(YourTextData){
//Put a debugger in here then check the argument
}
Use ng-model in your textbox to bind them to your scope variables
<input type="text" ng-model="value1">
<input type="text" ng-model="value2">
Then declare the variables inside your controller and use them in your function
$scope.value1 = 0;
$scope.value2 = 0;
$scope.add=function()
{
// Example
console.log($scope.value1 + $scope.value2);
}

Angularjs ng-required call function

It is possible make the required value dependet of some funcion?
Something like this? I want to do this because I want to change the required attribute to some form inputs...
HTML:
Name: <input type="text" ng-model="user.name" ng-required="isRequired('name')" />
Age: <input type="text" ng-model="user.age" ng-required="isRequired('age')" />
JS:
$scope.isRequired(fieldName){
$scope.requiredFields = [];
//$scope.requiredFields = STUFF FROM SOME REST SERVICE
for (i in requiredFields) {
if (requiredFields[i] == fieldName){
return true;
}
}
return false;
}
Updated Answer:
So based on your updated OP, what you want is certainly doable. The problem with what you were trying to do is that ng-required has no ability to execute a function, it only reads a boolean. But we can dynamically create variables based on data from the server to automatically set fields to required:
Updated Plunker
<form>
Name: <input type="text" ng-model="user.test" ng-required="name" /><br/>
<input type="text" ng-model="user.name" ng-required="age" />
<br/>
<button type="submit">Submit</button>
</form>
Note that I put a $scope property for each input in the ng-required attribute. Now we can dynamically create that $scope property and set it to true if our data says we need to:
$scope.isRequired = function(){
$scope.requiredFields = [];
$http.get('fields.json')
.success(function(data){
$scope.requiredFields = angular.fromJson(data);
console.log($scope.requiredFields.required)
for (i = 0; i < $scope.requiredFields.required.length; i++) {
$scope[$scope.requiredFields.required[i]] = true
}
console.log($scope[$scope.requiredFields.required[0]]);
})
//$scope.requiredFields = STUFF FROM SOME REST SERVICE
}
$scope.isRequired()
So it is iterating over an array of required fields received from the server, and then dynamically creating a $scope property for each one that is required, and setting it to true. Any field that has that $scope property in it's ng-required will be required now. Anything not dynamically created will just return false, and ng-required doesn't trigger.
Original answer:
Plunker
As Pratik mentioned, ng-required only accepts a Boolean value, but we can toggle the value of that with a function.
HTML
<form>
Name: <input type="text" ng-model="user.name" ng-required="isRequired" />
<br/><button ng-click="toggle()">Required: {{isRequired}}</button>
<button type="submit">Submit</button>
</form>
code:
$scope.isRequired = true;
$scope.toggle = function() {
$scope.isRequired = !$scope.isRequired;
}
I know this is a couple of years old and so AngularJS may have changed, but the accepted answer as it stands today isn't correct. You can very easily execute a function within ng-required, as it takes an expression, which can be a function. For example:
index.html
<div ng-controller="ExampleController" class="expressions">
Expression:
<input type='text' ng-model="expr" size="80"/>
<button ng-click="addExp(expr)">Evaluate</button>
<ul>
<li ng-repeat="expr in exprs track by $index">
[ X ]
<code>{{expr}}</code> => <span ng-bind="$parent.$eval(expr)"></span>
</li>
</ul>
</div>
script.js
angular.module('expressionExample', [])
.controller('ExampleController', ['$scope', function($scope) {
var exprs = $scope.exprs = [];
$scope.expr = '3*10|currency';
$scope.addExp = function(expr) {
exprs.push(expr);
};
$scope.removeExp = function(index) {
exprs.splice(index, 1);
};
}]);
In script.js, a function addExp is defined and added to the scope, and then it's called in the ng-click directive of the a tag, which also takes an expression as its argument.
This code is taken directly from the AngularJS documentation on expressions. It doesn't use ng-require directly, but any directive that takes an expression will work the same. I have used the same syntax to use a function for ng-require.

Angularjs - assigning logic between two models

I am new to Angular. It is a very simple question -
in my index.html I am defining two models on two text boxes :-
<html><head><script...></head><body ng-app="myApp"ng-controller="MainController" >
<input ng-model="tb1" type="text" name="numberofusers"/>
<input ng-model="tb2" type="text"></input>
</body></html>
And in my app.js I am defining like this
var app = angular.module('myApp', []);
app.controller('MainController', ['$scope', function($scope){
$scope.tb1 = $scope.tb2;
}]);
Now, what I want is that whatever I type in first text box (tb1) automatically typed to second text box (tb2) and vise-versa, but that is not happening.
Any guess ?
Your code in controller $scope.tb1 = $scope.tb2; would only be executed once (when controller initializes), that's why it doesn't work.
You need to bind input elements to the same model then Angular will handle two-way binding for you automatically.
<input ng-model="tb1" type="text" name="numberofusers"/>
<input ng-model="tb1" type="text"></input>
Or if you want to use two different models for different elements, you can add a hook to input's ng-change event listener like
<input ng-model="tb1" type="text" name="numberofusers" ng-change="tb2 = tb1"/>
<input ng-model="tb2" type="text" ng-change="tb1 = tb2"></input>
Then these two elements would sync automatically. But you know what, ng-change can only monitor user input change, that means, if you change tb1 or tb2 programmably, ng-change will not be triggered.
In this case, you should monitor model's change using $scope.$watch
$scope.$watch('tb1', function(newValue) {
$scope.tb2 = newValue;
}));
Currently it's beyond your requirement.
This is because controller will only execute once and if there is any value in $scope.tb2 will assign to $scope.tb1 but intially both of them are blank .
So you need to $watch the changes and assign value to each other like :-
$scope.$watch('tb1',function(newVal){
$scope.tb2=newVal;
})
$scope.$watch('tb2',function(newVal){
$scope.tb1=newVal;
})
And if you want to manage it on front end you can use ng-change directive like
<input ng-model="tb1" type="text" ng-change="tb2=tb1" name="numberofusers"/>
<input ng-model="tb2" type="text" ng-change="tb1=tb2"></input>
You can use two-way binding to achieve that. An example is: JSFiddle
Create your directive:
var app = angular.module('myApp', []);
app.controller("myCtrl", function($scope) {
$scope.myName = 'Carl';
}).directive("myDirective", function() {
return {
restrict: 'AE',
scope: {
twowayBindingProp: '=myName'
}
}
});
And bind it through:
<div ng-app="myApp">
<div ng-controller="myCtrl">
<h1>From parent: </h1>
<h3>parentProp2: <input ng-model="myName"></h3>
<div my-directive my-name="myName">
<h1>From child: </h1>
<h3>twowayBindingProp: {{ twowayBindingProp }}</h3>
<h1>Set from child:</h1>
twowayBindingProp: <input ng-model="twowayBindingProp">
</div>
</div>
</div>

Dynamic form name attribute <input type="text" name="{{ variable-name }}" /> in Angularjs

How would someone use formName.inputName.$valid when the "inputName" was dynamically created?
<form name="formName">
<input ng-repeat="(variable) in variables"
type="text" name="variable.name"
ng-model="variable.name" required />
</form>
The output of the HTML input attribute 'name' would be the string "variablename", which would applied to ALL repeated inputs.
If we tried this
<form name="formName">
<input ng-repeat="(variable) in variables"
type="text" name="{{ variable.name }}"
ng-model="variable.name" required />
</form>
The output of the HTML input attribute 'name' would be the string"{{ variable.name }}", which would be applied to ALL repeated inputs.
In either of these two conditions, a name attribute for each of the repeated input elements would not be created dynamically; ALL inputs would share the same input name. Not much good if you wanted to call a specific input based on a specific name.
need to use dynamic name values
need to be able to call $scope.formName.dynamicName.$valid
need to be able to call $scope.formName.$valid
need dynamic name input fields to be added to nested form, or master form
Looks like Angular 1.3 fixed this (https://stackoverflow.com/a/32907176/3854385)
This is now possible with Angular 1.3+:
<form name="vm.myForm" novalidate>
<div ng-repeat="p in vm.persons">
<input type="text" name="person_{{$index}}" ng-model="p" required>
<span ng-show="vm.myForm['person_' + $index].$invalid">Enter a name</span>
</div>
</form>
Demo
In some cases an inner form is a good solution if you can just pass the information: (https://stackoverflow.com/posts/12044600/)
To solve the 'dynamic name' problem you need to create an inner form (see ng-form):
<div ng-repeat="social in formData.socials">
<ng-form name="urlForm">
<input type="url" name="socialUrl" ng-model="social.url">
<span class="alert error" ng-show="urlForm.socialUrl.$error.url">URL error</span>
<button ng-click="doSomething(urlForm.socialUrl.$valid)">Test</button>
</ng-form>
</div>
The other alternative would be to write a custom directive for this.
Here is the jsFiddle showing the usage of the ngForm: http://jsfiddle.net/pkozlowski_opensource/XK2ZT/2/
I could not find the answer that satisfied some or all of these needs. This is what I came up with.
There may be a better way, so please share your thoughts.
I am using Angularjs 1.3.0-beta.8
I have a form with multi-nested directives that all contain input(s), select(s), etc...
These elements are all enclosed in ng-repeats, and dynamic string values.
This is how to use the directive:
<form name="myFormName">
<nested directives of many levels>
ex: <input ng-repeat=(index, variable) in variables" type="text"
my-name="{{ variable.name + '/' + 'myFormName' }}"
ng-model="variable.name" required />
ex: <select ng-model="variable.name" ng-options="label in label in {{ variable.options }}"
my-name="{{ variable.name + '/' + 'myFormName' }}"
</select>
</form>
Note: you can add and index to the string concatenation if you need to serialize perhaps a table of inputs; which is what I did. However, dynamic name inputs means you may not know the name of the form input, so how would you call $scope.formName.??????. You could iterate of the $scope.formName object to get keys that match a certain value. That means string concatenation like this:
my-name="{{ dynamicString + hello + '/' + 'myFormName' }}"
Then in $scope.myFormName you would find any form input name by just iterating over the object and gathering any keys that included 'hello'.
app.directive('myName', function(){
var myNameError = "myName directive error: "
return {
restrict:'A', // Declares an Attributes Directive.
require: 'ngModel', // ngModelController.
link: function( scope, elem, attrs, ngModel ){
if( !ngModel ){ return } // no ngModel exists for this element
// check myName input for proper formatting ex. something/something
checkInputFormat(attrs);
var inputName = attrs.myName.match('^\\w+').pop(); // match upto '/'
assignInputNameToInputModel(inputName, ngModel);
var formName = attrs.myName.match('\\w+$').pop(); // match after '/'
findForm(formName, ngModel, scope);
} // end link
} // end return
function checkInputFormat(attrs){
if( !/\w\/\w/.test(attrs.rsName )){
throw myNameError + "Formatting should be \"inputName/formName\" but is " + attrs.rsName
}
}
function assignInputNameToInputModel(inputName, ngModel){
ngModel.$name = inputName
}
function addInputNameToForm(formName, ngModel, scope){
scope[formName][ngModel.$name] = ngModel; return
}
function findForm(formName, ngModel, scope){
if( !scope ){ // ran out of scope before finding scope[formName]
throw myNameError + "<Form> element named " + formName + " could not be found."
}
if( formName in scope){ // found scope[formName]
addInputNameToForm(formName, ngModel, scope)
return
}
findForm(formName, ngModel, scope.$parent) // recursively search through $parent scopes
}
});
This should handle many situations where you just don't know where the form will be. Or perhaps you have nested forms, but for some reason you want to attach this input name to two forms up? Well, just pass in the form name you want to attach the input name to.
What I wanted, was a way to assign dynamic values to inputs that I will never know, and then just call $scope.myFormName.$valid.
This may be an overkill, and a better solution exists in 1.3+. I couldn't find it in the time I had. This works for me now.
Good luck! Hope this helps someone!!!!
work for me with angular 1.2.7
directive:
var DynamicName = function() {
return {
restrict: 'A',
priority: -1,
require: ['ngModel'],
link: function (scope, element, attr, ngModel) {
ngModel[0].$name = attr.name;
}
};
};
app.directive('dynamicName', DynamicName);
howtouse:
<div ng-repeat="phone in hrModel.phones">
<input type="text"
name="phones[{{$index}}]"
ng-model="phones[$index]"
dynamic-name
/>
</div>
Don't forget that you can access javascript objects using array notation with string indexes. Given the following arbitrary form definition object :
$scope.form_def = {
form_name : 'BallForm',
variables : [
height : { name : 'Height', type : 'text' },
width : { name : 'Width', type : 'text' },
color : { name : 'Color', type : 'multi', options : ['red', 'green', 'blue'] }
]
};
$scope.form_values = {};
... and the html snippet ...
<form name="{{ form_def.form_name }}">
<div ng-repeat="variable in form_def.variables">
<input ng-if="variable.type==='text'" type="text" name="{{ variable.name }}" ng-model="form_values[variable.name]">
<select ng-if="variable.type==='multi'" name="{{ variable.name }}" ng-model="form_values[variable.name]">
<option ng-repeat="opt in variable.options" value="{{ opt }}">{{ opt }}</option>
</select>
</div>
</form>
Inside the controller you then would have a nice form_values object for every field which you can access by iterating over the keys in the form_def.variables hash.
There is a lot more involved once you get down into writing these sort of generic form processing scripts and you end up with a hell of a lot of spaghetti code in my opinion and you would probably be better of going with a less general solution, but thats another SO question.

Trying to update one input's value to another's using angularjs

I'm fairly new using AngularJS but I've been using for a pet project and I've run in to an issue. What I basically want to do is take the text input from this input field:
<form id="ci_search_form">
<p class="input-append"><label>Search:</label> <input type="text" id="query" ng:model="query" autofocus> <button ng:click="clearSearch()" class="btn"><i class="icon-remove"></i></button></p>
</form>
and update this input field's value with that value:
<div><input type="text" id="ciquery" ng:model="ciquery.Name"></div>
The second input filters some data and I can type in that directly and it works. However this page will have different sets of data, each with their own search input that I want updated by the master input at the top. I can't set value="" or use jQuery to set the value either, it just appears blank unless I explicitly type in that second input field. Can anyone assist with a solution?
EDIT
I thought I should include my app and controller code:
var App = angular.module('TicketAssistApp', []);
App.controller('SearchController', function($scope, $http, $filter){
$scope.query = '';
$http.get('static/ci_list.json').success(function(data){
$scope.ci_list = data;
});
$scope.clearSearch = function(){
$scope.query = '';
}
});
EDIT 2
Made some progress. Created a function that can be called an update ciquery in $scope:
var App = angular.module('TicketAssistApp', []);
App.controller('SearchController', function($scope, $http, $filter){
$scope.query = '';
$scope.ciquery = '';
$http.get('static/ci_list.json').success(function(data){
$scope.ci_list = data;
});
$scope.queryUpdate = function(){
$scope.ciquery = $scope.query;
}
$scope.clearSearch = function(){
$scope.query = '';
$scope.queryUpdate();
}
});
This works great. However, this creates another issue. Before in ciquery I was using ciquery.Name to filter only on the Name attribute. With this new solution I had to change it to this:
<div><input type="hidden" id="ciquery" ng:model="ciquery"></div>
This searches all fields in my data which returns unwanted results. Suggestions?
$scope and ng-model are differents. You should give ng-model's property to ng-click's function. Looks at this -> Ng-model does not update controller value
To update second input's field (here an example -> http://jsfiddle.net/yEvSL/1/)
<div><input type="text" id="ciquery" ng:model="query"></div>

Categories