Retrieve all ngModels within a transcluded directive - angularjs

i'm trying to retrieve all ngModels within a transcluded directive. Is this the right way or is there a simpler solution to find the child model values?
Is there also a selector where i can use queries like this one ("input", "textarea", "select", ...)
The sample: http://plnkr.co/edit/tjjBEa1I1fIISvGbRz7e?p=preview

I don't know if this is the right approach. All your models are inside your $scope so why don't getting it from there directly?
For changes you shouldn't use jQuery like element.on('change', ...) style, instead bind an event listener to the model with $scope.$watch('model', ...) that would be the angular way.

Are you trying to disable all the inputs and clear their values when the 'Disable' checkbox is ticked?
I would recommend adding the ng-disabled directive to your inputs and binding it to a property on your model.
You can easily clear the input values by moving them onto an object on your model and then clearing that property when the controls are disabled.
Updated version of your plunkr: http://plnkr.co/edit/xKRF3rfAB8EcSKEBEeKd?p=preview
Here is the updated code based on your example:
app.js:
app.controller('MainCtrl', function($scope) {
// 1. Bind the 'Disable' checkbox's ng-model to this value.
$scope.disabled = false;
// 2. Move all your model data down one level onto the 'viewData' object.
// Now we can change all the input values just by changing the `$scope.viewData` object.
$scope.viewData = {
user: {
lastname: 'Doe',
firstname: 'John'
},
checker: true,
opt: 'Item 2'
};
// 3. Add a change callback on the 'Disable' checkbox to call this function.
// Replace the $scope.viewData to change the input values.
var originalData = null;
$scope.disabledChanged = function() {
if ($scope.disabled) {
// Clear the previous object.
originalData = $scope.viewData;
$scope.viewData = null;
} else {
// Revert back to the previous object.
$scope.viewData = originalData;
}
}
})
index.html:
<fieldset id="f">
<legend>
<label><input type="checkbox" child-disable child-disable-root="f" ng-model="disabled" ng-change="disabledChanged()" /> Disable</label>
</legend>
<hr />
<p><input type="checkbox" ng-model="viewData.checker" ng-disabled="disabled" /> Test</p>
<p><input type="text" ng-model="viewData.user.firstname" ng-disabled="disabled" />
<input type="text" ng-model="viewData.user.lastname" ng-disabled="disabled" /></p>
<p><textarea ng-model="viewData.multi" ng-disabled="disabled"></textarea></p>
<div>
<select ng-model="viewData.opt" ng-disabled="disabled">
<option>Item 1</option>
<option>Item 2</option>
<option>Item 3</option>
</select>
</div>
<div>
<button>Click</button>
</div>
</fieldset>

Related

Angularjs: How to get value of input without ng-model

I need to make some inputs by ng-repeat, and in my json file I have in object where is a property called name, like this:
"url":"find_company",
"values":[
{
"name":"company name",
"type":"input_search"
},{
"name":"company_phone",
"type":"input_search"
}
]
I want to make search in DB, in search you can find by any field or by two or more field. Field called the same as property of object. So by ng-keyup I need to send to my function
search(field, value)
two arguments. I want to do something like this
<div ng-repeat="value in param.values">
<input ng-if="value.type == 'input_search'"
ng-keyup="search(value.name, this.text)"
type="text">
How can a send to function text of this input without using ng-model? Where this.text is value of input.
since you are using ng-keyup, you can retrieve input value with $event.target.value.
comment: this is fit for normal event like onclick, but not fit for angular.
refer the below example.
angular.module("app", [])
.controller("myCtrl", function($scope) {
$scope.showValue = function(val) {
alert(val);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
<input type="test" ng-keyup="showValue($event.target.value)">
</div>
This is how you do it with ngModel:
<div ng-repeat="value in param.values">
<input ng-if="value.type == 'input_search'" ng-model="value.val" ng-keyup="search(value)" type="text">
And in your controller:
$scope.search = function( item ) {
console.log( item.val ); // Here you have the value using ngModel
console.log( item.name ); // Here you have the "name" property of the element inside the loop
}
As you can see, you CAN use ngModel and by passing the object itself to the function you can access its properties from the function in the controller.
Note that there's that this.text in the view - I don't know what it is exactly so I dropped it from the example to make things clearer, but you can use it in your code of course.
I know the question said without using ng-model. But I suspect you may want this because you want to customize when data-binding occurs. If that's the case, you can use ng-model-options with ng-change:
<input type="text" ng-model="yourModel" ng-model-options="{ updateOn: 'keyup' }" ng-change="search()" />
ng-change fires when the model has been updated, which is after keyup in this case. So the value of yourModel will be up to date when search() executes.

Based on dropdown value show div inside ng-repeat

The below thing is taking too much time than expected. Been through top stack solutions and somehow got the below thing--
WHAT IS THE SCENERIO
I have an ng-repeat div with dropdown.
The drop down contains values and based on selection of those values a div will be shown. What I managed is div is shown. But when I choose another item the previous item div gets hidden.
Below are the screen shot and my code
As it can be seen that when I select the first item it shows the textbox div. But when I select the next item the first gets hidden. There are essentially two values -- ALL, Fixed. When All selected nothing will be shown and when Fixed is selected the div for that particular item will be shown.
HTML code
<div class="tst text-success" ng-repeat="(parentIndex, catList) in categoryArray">
<div class="col-md-3">
{{catList.categoryName}}
</div>
<div class="col-md-4">
<select class="form-control m-b" ng-model="catObj.cats" ng-change="changeOption(catObj,parentIndex)">
<option value="All">All</option>
<option value="fixed">Fixed No. Of Records</option>
<option value="perfixed">% od Fixed</option>
</select>
</div>
<div class="col-md-3 noPad" ng-if="isShowing==parentIndex">
<input type="text" class="form-control form-control-small" placeholder="Set Number" />
</div>
</div>
CONTROLLER
$scope.changeOption = function(obVal,index) {
console.log(obVal);
console.log(index);
if(obVal.cats == "All") {
//$scope.tbx = 0;
}
else {
$scope.isShowing = index;
}
}
Help would be appreciated
Thanks
You're using a single boolean $scope variable, isShowing, to control the visibility of several divs. That can't possibly work.
You should
have an array of objects, each having a selectedOption field.
use ng-model in your select box to set the selectedOption of the object you're editing.
use the value of the object's selectedOption to know if the additional input should be visible for that object.
Example:
<div ng-repeat="obj in objects">
{{ obj.name }}
<select name="op" ng-model="obj.selectedOption" ng-options="option.value as option.value for option in options"></select>
<input ng-if="obj.selectedOption !== 'All'" />
</div>
app.controller('MainCtrl', function($scope) {
$scope.options = [
{value: 'All'},
{value: 'Fixed'}
];
$scope.objects = [
{name: 'Twitter', selectedOption: 'All'},
{name: 'News', selectedOption: 'Fixed'}
]
});

Angular : pass mutliple values to the controller

Let's say i have a drop drown list that i add dynamicly in my html template:
<button type="button" ng-click="addRow()" style="margin-bottom:5px;">Add cities </button>
<div ng-repeat="city in cities">
<select ng-model="cities_$index"
ng-options="n.id as n.name for n in citiesList"
class="form-control"
ng-required="true">
<option value="">-- Choose City --</option>
</select>
</div>
Angular Controller :
$scope.addRow = function () {
var newrow = [];
if ($scope.cities.length === 0) {
newrow.push({ 'cities': $scope.cities_0 });
}
else {
$scope.cities.forEach(function (row, key) {
var city= '$scope.cities_'+key; // in php i can do this
//but i dont know how to do it with Js/Angular
console.log('row' + city);
newrow.push({ 'cities': city});
console.log(newrow);
});
}
$scope.cities.push(newrow);
}
I tried this to retrieve the values from the cities selected but i have undefined values.
$scope.send = function () {
angular.forEach($scope.cities, function (value, key) {
console.log(value.id); // the id from the ng-options
};
In a regular html code i just add name="city" and i retrieve all the cities added in my input box. But how i can retrieve thoses cities from the ng-model in my controller ?
I know i'm doing something wrong, but since i'm new with angular i'm trying !!
Thank you
supposing that the key (city) is inside your datas array, you can do :
<div ng-repeat="data in datas">
<input type="text">{{data.name}}
</div>
ng-model is still unique. What you are missing here is that ng-repeat creates a child scope for each item. Therefore, the value of ng-model is unique for EACH child scope. ng-model doesn't behave the same way as plain HTML input and having multiple inputs with the same ng-model will only point to the same object in memory. And not, "add up" values to the property city as you would expect in plain HTML inputs.
If you are using the object datas in your ng-repeat, it's kind of common practice that your <input /> would bind to a item property of datas.
<div ng-repeat="data in datas">
<input type="text">{{data.city}}
</div>

How to set radio button in angularjs with Object

I have created radio buttons in angularjs using array of objects using ng-value and ng-model.
`
<div ng-controller="DemoController">
<div ng-repeat="detail in details">
<input type="radio" ng-model="$parent.selectedVal" ng-value="detail" name="test">
</div>
{{selectedVal}}
</div>
`
On selection of radio button model is populated with corresponding object value. But I am not sure how to initialize it using controller with object.
var app = angular.module('myApp', []);
app.controller("DemoController",DemoController);
function DemoController($scope) {
$scope.selectedVal={name:"Def",age:4} ;
$scope.details=[{name:'Abc',age:2},{name:'Xyz',age:3},{name:'Def',age:4}];
}
You should reference the selected value from the details array instead of creating a new instance:
$scope.details = [{ name:'Abc', age:2 }, { name:'Xyz', age:3 }, { name:'Def', age:4 }];
$scope.selectedVal = $scope.details[2];
This will select the last of the 3 radio buttons. Also if both details and selectedVal are defined within the same scope you should update your radio button as well, it's quite unclear why you referenced selectedVal from a $parentScope:
<input type="radio" ng-model="selectedVal" ng-value="detail" name="test" />
And here's the updated fiddle: https://jsfiddle.net/sb3krc8c/2/

why $viewValue === $modelValue on select?

http://plnkr.co/edit/iVvvdbvI3it7KrYZW6mK
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.selectModel = '1';
$scope.inputModel = new Date();
$scope.testOptions = [
{key: '1', description: 'text 1'},
{key: '2', description: 'text 2'},
{key: '3', description: 'text 3'}
];
});
.
<body ng-controller="MainCtrl">
<form name="inputForm">
<strong>how $viewValue works for input</strong><br />
<input type="date" name="input" ng-model="inputModel"/>
<div>$viewValue: {{inputForm.input.$viewValue}}</div>
<div>$modelValue: {{inputForm.input.$modelValue}}</div>
</form>
<br /><br /><br />
<form name="selectForm">
<strong>how $viewValue works for select</strong><br />
<select name="select" ng-model="selectModel" ng-options="item.key as item.description for item in testOptions"></select>
<div>$viewValue: {{selectForm.select.$viewValue}}</div><!--shows '1', i expected 'text 1'-->
<div>$modelValue: {{selectForm.select.$modelValue}}</div><!--shows '1', as expected-->
</form>
</body>
In the above plunker, you can see different meaning of $viewValue for input vs select.
For input, $viewValue is the string user is seeing, $modelValue is data model.
For select, $viewValue and $modelValue are equal, both being data model.
That does not make any sense to me. Why is that?
To clarify, my question is about select element, specifically: where does $viewValue come from (it seems to always equal $modelValue), and why it isnt actual text displayed in select element?
The nature of $viewValue is determined by the directive. The $render method brings the view value to the screen and if the user can change a value, the directive converts the user's input to the view value. How that happens is completely up to the directive.
The default implementation of $render e.g. is empty. The implementation for input simply sets the value of the element:
element.val(ctrl.$isEmpty(ctrl.$modelValue) ? '' : ctrl.$viewValue);
That's why $viewValue is equal to the value that is being displayed. The implementation for select is more complex because you have a lot of options (pun intended). When you use ng-options the HTML that's generated is like this:
<option value="0" selected="selected" label="text 1">text 1</option>
<option value="1" label="text 2">text 2</option>
<option value="2" label="text 3">text 3</option>
As you can see the actual value is a simple index, barely related to your model. Furthermore the selection tag allows multiple selections. So you have several different possibilities as to what the view value is. I guess it was easiest to let $viewValue be equal to the model value.
FWIW: Imagine a custom directive that uses ng-model but does not directly display a value, like a custom slider. It makes perfectly sense to not use a separate view value but simply use the model value.
$viewValue is the inputElement.value which is provided by the browser.
As the input type is Date angular's built-in ngModel parsers will parse the $viewValue will convert it to date and then assign it to model.
Code snippet from AngularJS
ctrl.$parsers.push(function(value) {
if(ctrl.$isEmpty(value)) {
ctrl.$setValidity(type, true);
return null;
}
if(regexp.test(value)) {
ctrl.$setValidity(type, true);
return parseDate(value);
}
ctrl.$setValidity(type, false);
return undefined;
});

Resources