I'm new to Angular and can't figure out what I am doing wrong while trying to get ng-model to display an object value.
The goal:
I want to create a directive that reads an Object and generates radio buttons based on Object data. Inside of this Object I have {logAs: 'radioGroupName'}. This should get stored into another object called formData.
Example:
{logAs: 'dog', options: [{option: 'poodle'}, {option: 'pitbull'}]}
This should create two radio buttons, one for pittbull and another for poodle. Both should have ng-model set to dog. If user selects Poodle then final output in the formData Object should be:
{dog: 'poodle'}
The Issue:
I believe I am close, everything works fine except for ng-model. Inside of ng-model the actual Object value (dog) wont show up as I'd like, instead I get the Object path that I typed in.
This is my html:
<div ng-app="test">
<div ng-controller="myController">
<p>formData: {{formData}}</p>
<h3>Static (updates formData)</h3>
<input type="radio" ng-model="formData.dog" value="pitbull"> Pitbull<br/>
<input type="radio" ng-model="formData.dog" value="Bull Dog"> Bull Dog<br/>
<input type="radio" ng-model="formData.dog" value="Poodle"> Poodle
<h3>Dynamic (wont update formData)</h3>
<directive form="formInfo"></directive>
</div>
This is the Javascript:
angular.module('test', [])
.controller('myController', function($scope){
$scope.formData = {};
$scope.formInfo = {
title: 'What type of dog do you have?',
logAs: 'dog',
options: [{option:'Pitbull'}, {option: 'Bull Dog'}, {option:'Poodle'}]
}
})
.directive('directive', function(){
return {
restrict: 'E',
template: '{{form.title}}<div ng-repeat="option in form.options"> <input type="radio" ng-model="form.logAs" value="jack" > {{option.option}}</div>',
scope: {
form: '='
}
}
});
How can I get ng-model to show the output of the object ('dog') instead of the object path?
Here is a fiddle
In your fiddle, it's because on line 3 of your html, you have {{formData}} when it should be {{formData.dog}}
Related
I'm experiencing some problems while inputing user data into ordered fields displayed with Angular ng-repeat.
Say that you want some values to display on a list, and those values might be editable. At the same time, you are ordering that data. Due to how ng-model works and Angular reflow cycle, if the value of one input surpases another one while still editing, you'll find yourself typing on the wrong field. Look at this example:
var app = angular.module('app', []);
app.directive('myrow', Row);
app.controller('controller', Controller);
function Controller () {
this.order = '-value';
this.inputs = [
{value: 1, tag: "Peas"},
{value: 2, tag: "Apples"},
{value: 3, tag: "Potatos"}
];
}
function Row($compile, $sce){
var linker = function($scope, $element, $attrs){
var template = '<div>- <input type="number" ng-model="data.value"><span ng-bind="data.tag"></span></div>';
a = $element.html(template);
$element.html(template);
$compile($element.contents())($scope);
}
return {
restrict: 'AE',
replace: true,
scope: {
data: "="
},
link: linker
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<div ng-app="app" ng-controller="controller as ctrl">
List:
<div ng-repeat="item in ctrl.inputs | orderBy: ctrl.order">
<div myrow data="item"></div>
</div>
</div>
I've made this simplified example as the original component has thousands of lines and some dependencies. Here this problem is not reproduced exactly, yet, when you write, sometimes the input loses focus, thing that, for example, doesn't happen when not compiling on the directive (which is completly necessary in my real code). Any ideas on how to solve this? Is it possible to activate ng-model update on change instead of on user typing.
You can use ng-model-options and its updateOn property so that your model is updated only when user leaves the field.
You can see how it works here: https://docs.angularjs.org/api/ng/directive/ngModelOptions (There is a sample in the 'Triggering and debouncing model updates' section)
example:
<input ng-model-options="{ updateOn: 'blur'}" />
I want to make multiselect checkbox using ng-repeat. It is working fine if I don't have pre-selected checkbox. But when I have preselected checkbox then its behaviour is totally unusual.
<div ng-repeat="account in accounts">
<input ng-model="selectedAccounts[account.id]"
ng-checked="{{account.lastchecked}}" type="checkbox">
</div>
In Controller I got selected id as:
$scope.selectedAccounts = [];
angular.forEach($scope.selectedAccounts, function(value, key) {
if(value == true) {
selectedIds.push(key);
}
});
The problem here is that I have to initialise selectedAccounts with initial array. If I don't do this then it gives me undefined. When I have 'lastchecked' true for some accounts then it shows pre-checked values according to lastchecked but when I try to retreive $scope.selectedAccounts it give me empty array. But when I manually check/uncheck each option then $scope.selectedAccounts give me correct result.
Here is how i would do it :
$scope.context = {accounts : :[]};// init is important to place the variable in that scope on not in a child
<div ng-repeat="account in context.accounts">
<input ng-model="account.lastchecked" ng-checked="account.lastchecked"
ng-true-value="true" ng-false-value="false" type="checkbox">
</div>
Ng-true-value and ng-false-value ensure that the value will be the boolean true/false instead of strings.
After to get the selectedAccount you just search.filter account with lastchecked==true
The indermediary object context is to avoid scope issues, scope inheritance fails on simple fields. This is a limit of javascript. In angularJS this is called DOT notation.
Go through this
var jimApp = angular.module("mainApp", []);
jimApp.controller('mainCtrl', function($scope){
$scope.selectedAccounts = {"3":true};
$scope.accounts = [{id:1, name:"account1", checked: true}, {id:2, name:"account2"}, {id:3, name:"account3"}]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="mainApp" ng-controller="mainCtrl">
<div ng-repeat="account in accounts">
<input ng-model="selectedAccounts[account.id]"
ng-checked="selectedAccounts[account.id]" type="checkbox">{{account.name}}
</div>
<div>{{selectedAccounts}}</div>
</div>
Say I have the following directive called foo:
<div>
<label>Enter foo: </label>
<input ng-model="myModel"/>
</div>
And I use it like so:
<foo></foo>
<button>Add foo: </button>
What I am trying to do is dynamically add the foo directive on each button click and be able to have access to the new model variable that was created in the corresponding controller for this page.
Can this be done using angularJS?
First of all, if you plan to re-use <foo>, then you should create an isolated scope:
.directive("foo", function(){
return {
restrict: "E",
scope: {
data: "="
},
template: "<div><label>Enter foo: </label><input ng-model='data'/></div>"
}
});
There is no difference between creating a custom directive or other tags. Without knowing too much about what you're doing, I could suggest the following:
app.controller("MainCtrl", function($scope)){
$scope.fooModels = [];
$scope.addFoo = function(){
$scope.fooModels.push(new FooModel());
};
}
FooModel() here is just a placehold for whatever the data model you need to represent foo data. You could also just do: $scope.fooModels.push({});.
Then in the view, simply ng-repeat your fooModels:
<div ng-repeat="fooModel in fooModels">
<foo data="fooModel.data"></foo>
</div>
<button ng-click="addFoo()">Add Foo</button>
Here's a plunker to play with.
I want to do something like this
<input type="checkbox" ng-model="first" ng-click="chkSelect()"/><label>First</label>
<input type="checkbox" ng-model="second" ng-click="chkSelect()"/><label>Second</label>
<input type="checkbox" ng-model="third" ng-click="chkSelect()"/><label>Third</label>
<input type="checkbox" ng-model="forth" ng-click="chkSelect()"/><label>Forth</label>
<button>Selected</button>
On button click I want to display selected checkbox labelname.
$scope.chkSelect = function (value) {
console.log(value);
};
Because the checkboxes are mapped, you can reference $scope.first, $scope.second, etc in your chkSelect() function. It's also possible to have a set of checkboxes mapped as a single array of data instead of having to give each checkbox a name. This is handy if you are generating the checkboxes, perhaps from a set of data.
I agree with Bublebee Mans solution. You've left out a lot of detail on why you're trying to get the label. In any case if you REALLY want to get it you can do this:
$scope.chkSelect = function (value) {
for(var key in $scope){
var inputs = document.querySelectorAll("input[ng-model='" + key + "']");
if(inputs.length){
var selectedInput = inputs[0];
var label = selectedInput.nextSibling;
console.log(label.innerHTML);
}
};
};
You can mess around with it to see if it's indeed selected.
fiddle: http://jsfiddle.net/pzz6s/
Side note, for anybody who knows angular please forgive me.
If you are dealing with server data, you might need isolated html block and deal with data in controller only.
You can do it by creating array in controller, maybe your data from response, and use ngRepeat directive to deal independently in html code.
Here is what I am telling you:
HTML:
<form ng-controller="MyCtrl">
<label ng-repeat="name in names" for="{{name}}">
{{name}}
<input type="checkbox"
ng-model="my[name]"
id="{{name}}"
name="favorite" />
</label>
<div>You chose <label ng-repeat="(key, value) in my">
<span ng-show="value == true">{{key}}<span>
</label>
</div>
</form>
Javascript
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.names = ['pizza', 'unicorns', 'robots'];
$scope.my = { };
}
You want to have something like the following in your controller (untested, working from memory):
$scope.checkBoxModels = [ { name: 'first', checked: false }, { name: 'second', checked: false }, { name: 'third', checked: false }, { name: 'fourth', checked: false } ];
Then in your view:
<input ng-repeat"checkboxModel in CheckBoxModels" ng-model="checkBoxModel.checked" ng-click="chkSelect(checkBoxModel)" /><label>{{checkBoxModel.name}}</label>
Then update your function:
$scope.chkSelect = function (checkBoxModel) {
console.log(checkBoxModel.name);
};
I have a form, within there are different input-tags and labels :
form action="">
<div class="fields" data-ng-repeat="option in question.body.options">
<input id="{{option.text}}" type="radio" name="gender" ng-model="demographic_value" ng-value="{{option.text}}">
<label for="{{option.text}}">{{option.text}}</label>
</div>
</form>
I want to access the value of the selected radio button, how is the data binded? Is there any standard-method, or "isChecked" value or something like that?
EDIT: OK, to be more clear: I want to have only the option which is selected. Inside the controller, not in the view.
So i can send the selected value over HTTP to a server.
Click a radio button
do something like var checked = $scope.radiobutton
array.push(checked)
Send over to a server
Use a shared service and inject it to any controllers:
angular.module("yourAppName", []).factory("mySharedService", function(){
var mySharedService = {};
mySharedService.values = {};
mySharedService.setValues = function(params){
mySharedService.values = params;
}
return mySharedService;
});
And after inject it into any controller.
For example:
function MainCtrl($scope, myService) {
$scope.radioButtons= myService.values;
}
function AdditionalCtrl($scope, myService) {
$scope.var= myService.values;
}
EDIT: as for checked/unchecked values:
You can use watcher:
$scope.$watch('question.body.options', function (changedOptions) {
//some actions with changed options
}, true);
UPDATE:
As for your update:
1) You should create watcher, such as above.
2) Into the watcher, when value changes - you initialize necessary service property with your values (call setValue function)
3) You should inject sharedService into another controller, and can get these values from this service.
4) Call $http or $resource method to sent this value on server.
ng-repeat creates its own scope for each item, so you might have problem accessing it. Try put the model in an object from parent scope.
ng-value accepts expression but not like {{expression}}.
http://jsfiddle.net/g8qLY/
HTML:
<form ng-app ng-controller="ctrl" name="inputform">
<label for="{{option}}" ng-repeat="option in options">
{{option}}
<input id="{{option}}" type="radio" name="gender"
ng-model="inputform.radioinput" ng-value="option">
</label>
<div ng-bind-template="Radio Input: {{inputform.radioinput}}"/>
</form>
JS:
function ctrl($scope) {
$scope.options = ['Option1', 'Option2', 'Option3'];
}