AngularJS - Find all ngModel in the current scope - javascript

I have a HTML template like this:
<div ng-controller="MyCtrl">
<input ng-model="model.name" /> {{model.addr}}
<button ng-click="detect()">detect</button>
</div>
And this is the controller:
function MyCtrl($scope) {
$scope.detect = function() {
var fields = []; //['model.name', 'model.addr']
//call server with selected fields
}
}
The template can be customized by user and generated dynamically, not static template. I want to optimize the data model returned from server, only return values for needed fields in the template. The idea is I want to get all the ng-model fields from template and pass them to the server. The returned data will contain only values for these fields, instead of whole data model, for example:
{
name: 'Superhero',
addr: 'Mars'
}
If I change the template like this (remove model.addr):
<div ng-controller="MyCtrl">
<input ng-model="model.name" />
<button ng-click="detect()">detect</button>
</div>
The fields array should be ['model.name'] and the returned data from the server should be:
{
name: 'Superhero'
}
There are any ways to get all ng-model fields in the scope?
Thanks!

You can do 1 thing, wherever you are using ng-modal, take an object modal and assign values by using dot(.).
Suppose
<div ng-controller="MyCtrl">
<input ng-model="model.name1" />
<input ng-model="model.name2" />
<input ng-model="model.name3" />
<button ng-click="detect()">detect</button>
So you can get model in scope hence all the attributes of scope.

Related

Binding ngModel to expression's value

I have a scenario in which the property ng-model should bind to value that comes from database as a part of business logic.
For simplicity, I have created this example
function TodoCtrl($scope) {
$scope.field1 = "PropertyFromDB";
$scope.PropertyFromDB = "hello world";
}
<div ng-app>
<h2>ngModel BINDING EXAMPLE</h2><br/>
<div ng-controller="TodoCtrl">
<div ng-init="imod = field1">
<input type="text" ng-model="imod"></input>
</div>
</div>
</div>
In this example, field1 is the value which will be property that comes from DB (i.e. PropertyFromDB) and ng-model should bind to PropertyFromDB instead of field1.
So, its like I want to evaluate expression inside expression syntax of ng-model but I am unable to do so.
Thanks
You can refer to the current scope with this and read its property, like:
<div ng-init="imod = field1">
<input type="text" ng-model="this[imod]"></input>
</div>
but it is a very unusual and inconvenient way to create a View Model.
I suggest creating a better structure/object that contains the field/value combination and setting that object on the scope, instead of setting field and value separately the scope.
You simply cannot set value of ng-model by using any expression. The alternative would be to change the stucture of the JSON which you returned from server.
Markup
<div ng-controller="TodoCtrl">
<div ng-repeat="field in properties">
<label>{{field.property}}</label>
<input type="text" ng-model="field.value" />
</div>{{properties}}
</div>
Code
function TodoCtrl($scope) {
$scope.properties = [{
property: 'PropertyFromDB',
value: "hello world"
}, {
property: 'PropertyFromDB1',
value: "hello world1"
}]
}
Fiddle Here

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.

Pass Model to Controller to Change in Controller

Here is my situation, I have this HTML:
<input type="text" ng-model="inputModel" />
<div class="button-container">
<button type="button" ng-click="setValue(inputModel)"></button>
</div>
<input type="text" ng-model="inputModelTwo" />
<div class="button-container">
<button type="button" ng-click="setValue(inputModelTwo)"></button>
</div>
And my view controller:
$scope.setValue = function (valueToSet) {
valueToSet = "Some value.";
};
I need to be able to "connect" the input fields and their buttons and I'm doing this by having the respective button pass the respective input field's model to the controller to be modified. The problem is that when I click the button the function fires off and valueToSet is changed but the change isn't reflected back in the view! What am I missing?
If you are trying to dynamically pass in your models as a function parameter, you'll need to access a PROPERTY on the models by using dot notation.
Try defining the models in the controller like so:
$scope.inputModel = {};
$scope.inputModelTwo = {};
$scope.inputModel.text = 'hey';
$scope.inputModelTwo.text = 'ho';
Then pass in the entire model to the function as you were already doing.
Inside the function, alter the property that you desire (in this case 'text'), like so:
$scope.setValue = function (valueToSet) {
console.log(valueToSet);
valueToSet.text = "Some value.";
};
JSFiddle

How can I concatinate a ng-model value with a value from a ng-repeat

I want to loop through an array of objects that I receive from a REST service and create a dynamic form using the ng-repeat directive.
This is my form with a rating directive (taken for the UI Bootstrap library)
<form name="categoryRatingFrom" data-ng-submit="updateCategories(catRatings) >
<div data-ng-repeat="cats in categories" class="form-group clearfix">
<label class="control-label">{{ cats.name }}</label>
<div class="no-outline"
data-rating
data-ng-model=" // Here I want to concatenate {{ cats.id }} with the ng-model name catRatings // "
data-max="6"
data-rating-states="ratingOptions.ratingStates"
data-on-hover="atmosphereRating.onHover(value)"
data-on-leave="atmosphereRating.onLeave()"></div>
</div>
<form>
I want to set the data-ng-model value using the object name that I pass when submitting and the ID of the current object tin my loop/array, however I don't seem to be able to do this. Should I do the concatenation in the controller on receiving the object array using a loop and then set the data-ng-model using a value from the ng-repeat nothing is passed to the controller when submitting the form (see my code below):
// loop through the object adding a ng-model name that we match in our form...
for (var i = 0, l = $scope.categories.length; i < l; i++) {
$scope.categories[i]['modelId'] = 'catRatings.' + $scope.categories[i].id;
}
I add the following to my HTML data-ng-model="cats.modelId" but nothing is passed to the controller when submitting - can any one help me with a solution or give me an answer to what I am doing wrong?
ng-model takes a variable, not a string value. I'm not sure what exactly you're trying to do but I would think it would be something like:
ng-model="catRatings[cats.id]"
However, I am not familiar with that directive so I'm not sure if it accepts a ng-model attribute.
I have created an example that will be referenced throughout the post. The following variables are declared within the scope as follows.
$scope.data = [
{
'id' : 0,
'name' : 'Tim'
},
{
'id' : 1,
'name' : 'John'
}
];
$scope.ratings = [ '5 stars', '2 stars' ];
When you are setting your model to 'catRatings' + {{ cats.id }} that means somewhere you are declaring a $scope.catRatings1, $scope.catRatings2, etc. Instead you should bind directly the the category object as follows.
<label ng-repeat="person in data">
<input type="text" ng-model="person.name">
...
</label>
or bind to an array with a corresponding index
<label ng-repeat="person in data">
...
<input type="text" ng-model="ratings[$index]">
</label>
or bind to an array using the id...
<label ng-repeat="person in data">
...
<input type="text" ng-model="ratings[person.id]">
</label>

AngularJS display alert depending on input value

I am coding a CRUD application in Angular and Web API.
In the create/edit form (same template), I need to display an error message if 2 input fields don't have the same number of comma ','.
I found a way to make it work but I don't like it, I think it needs to be "angularized" but I don't know how.
Controller:
$scope.isColumnCountOk = true;
$scope.checkColumnCountOk = function () { $scope.isColumnCountOk = AdminUtils.isColumnCountOk($scope.item.columnSqlNames, $scope.item.columnTitles) };
Template:
<input type="text" class="form-control" ng-model="item.columnTitles" placeholder="Report Column 1,Report Column 2,Report Column 3,..." ng-blur="checkColumnCountOk()" required />
<div ng-hide="isColumnCountOk">
<br />
<div class="alert alert-danger" ><strong>Warning. </strong>Mismatch between column numbers</div>
</div>
I would like to get rid of the $scope.isColumnCountOk and have the function called directly from the template, without storing the return value in the scope.
Any advice?
Bruno
I think both of these ways should work...
$scope.isColumnCountOk = function () {
return AdminUtils.isColumnCountOk($scope.item.columnSqlNames, $scope.item.columnTitles);
};
<div ng-hide="isColumnCountOk()">
...
</div>
Or
$scope.isColumnCountOk = AdminUtils.isColumnCountOk;
<div ng-hide="isColumnCountOk(item.columnSqlNames, item.columnTitles)">
...
</div>

Categories