I'm making a basic todo app in angularjs.
Here's the code that's used to create a new todo with a checkbox
<div class="container" ng-controller = 'controller' >
<h3>Enter Todo </h3> <input type="text" ng-model = 'new'>
<button ng-click = 'add();' ng-disabled="status();">Add</button>
<div ng-repeat = "i in todo" >
<input type="checkbox" ng-model = "todo.done" /> <label>{{i.name}}</label>
</div>
</div>
The problem is that all the checkboxes get checked even when I check just one
Here's my controller module
todoApp.controller('controller',['$scope',function($scope){
$scope.new = '';
$scope.todo = [];
$scope.add = function(){
$scope.todo.push({name : $scope.new, done: false});
console.log($scope.todo);
$scope.new = '';
};
$scope.status = function(){
return !(/\S+/.test($scope.new));
};
ng-model = "i.done"
should solve the problem. In your version ng-model = "todo.done" todo is an array and angular just creates a property on the fly, when it's used for the first time. This way all of your checkboxes are connected to this property, that's why checking one checkbox affects all of them.
Because the list of the checkbox are sharing the same model. You can create a custom directive or you can use checklist-model directive.
Demo URL:
https://vitalets.github.io/checklist-model/
Angular 1.*
I have:
<div class="filter-column">
<div class="filter-title">Market</div>
<div class="bottom-line"></div>
<div class="overflow-container">
<input type="radio" value="all" name="marketRadio"
ng-checked="true" class="resetAll" ng-model="filter.markets"
ng-change="radioMap('market')" checked>All
<div ng-repeat="choice in markets| orderBy: 'name'">
<input type="radio" value="{{choice.name}}" name="marketRadio"
ng-change="radioMap('market')" ng-model="filter.markets" >
{{choice.description}}
</div>
</div>
In the controller I have:
var ppvFilter = {
regions: [],
markets: [],
dealers: []
};
$scope.$watchCollection(function() {
return ppvFilter;
},
function(newValue) {
$scope.regions = newValue.regions;
$scope.markets = newValue.markets;
$scope.dealers = newValue.dealers;
});
When I refresh the radio button list programaticly(not page refresh) with ppvFilter.markets.length = 0; ppvFilter.markets = ppvFilter.markets.concat(['a', 'b', 'c']), the list of radio button choices updates as it should in the gui. However, ng-checked="true" no longer works for all and it is unchecked after the list updates.
I suspect it is because the angular form is referencing old memory even though it is showing the new list of radio buttons.
From the angular documentation on ngChecked: Note that this directive should not be used together with ngModel, as this can lead to unexpected behavior.
I figured it out.... the default item HAS to be in the ng-repeat. ng-check is not much use in real life.
Reference:
Radio button checked by default when using ng-repeat
View
<button class="ion-ios-close-outline" ng-click="change()"></button>
<label class="item item-input">
<input id='test' type="text" ng-value="77"/>
</label>
Controller
$scope.change = function () {
var x=angular.element(document.getElementById("test"));
alert(x.value);
};
The output is undefined.
What am i doing wrong in here?
Please help.
angular.element returns wrapper of jQlite. It's similar to jquery. So it doesn't support value.
Either use
x.val()
or
x[0].value
Either way i would recommend not to use such type of changes in controller. It should be done only in directives.
You should use model of input box to access such values in controllers.
Use ng-model on your input;
set ng-model='test'
<input id='test' type="text" ng-model='test' ng-value="77"/>
and on the change function set
var x=$scope.test;
alert(x);
Edited
var a = angular.element(document.getElementById('t'));
var attr = a[0].attributes;
var value = attr.getNamedItem("ng-value");
console.log(value.value);
In my opinion your solution is bad.
Angular API allow to use data binding.
So you should use ng-model in you input compoment for example:
<button class="ion-ios-close-outline" ng-click="change()"></button>
<label class="item item-input">
<input id='test' type="text" ng-model="test"/>
$scope.test = 77;
$scope.change = function () {
alert($scope.test);
};
For a specific use case I have to submit a single form the "old way". Means, I use a form with action="". The response is streamed, so I am not reloading the page. I am completely aware that a typical AngularJS app would not submit a form that way, but so far I have no other choice.
That said, i tried to populate some hidden fields from Angular:
<input type="hidden" name="someData" ng-model="data" /> {{data}}
Please note, the correct value in data is shown.
The form looks like a standard form:
<form id="aaa" name="aaa" action="/reports/aaa.html" method="post">
...
<input type="submit" value="Export" />
</form>
If I hit submit, no value is sent to the server. If I change the input field to type "text" it works as expected. My assumption is the hidden field is not really populated, while the text field actually is shown due two-way-binding.
Any ideas how I can submit a hidden field populated by AngularJS?
You cannot use double binding with hidden field.
The solution is to use brackets :
<input type="hidden" name="someData" value="{{data}}" /> {{data}}
EDIT : See this thread on github : https://github.com/angular/angular.js/pull/2574
EDIT:
Since Angular 1.2, you can use 'ng-value' directive to bind an expression to the value attribute of input. This directive should be used with input radio or checkbox but works well with hidden input.
Here is the solution using ng-value:
<input type="hidden" name="someData" ng-value="data" />
Here is a fiddle using ng-value with an hidden input: http://jsfiddle.net/6SD9N
You can always use a type=text and display:none; since Angular ignores hidden elements. As OP says, normally you wouldn't do this, but this seems like a special case.
<input type="text" name="someData" ng-model="data" style="display: none;"/>
In the controller:
$scope.entityId = $routeParams.entityId;
In the view:
<input type="hidden" name="entityId" ng-model="entity.entityId" ng-init="entity.entityId = entityId" />
I've found a nice solution written by Mike on sapiensworks. It is as simple as using a directive that watches for changes on your model:
.directive('ngUpdateHidden',function() {
return function(scope, el, attr) {
var model = attr['ngModel'];
scope.$watch(model, function(nv) {
el.val(nv);
});
};
})
and then bind your input:
<input type="hidden" name="item.Name" ng-model="item.Name" ng-update-hidden />
But the solution provided by tymeJV could be better as input hidden doesn't fire change event in javascript as yycorman told on this post, so when changing the value through a jQuery plugin will still work.
Edit
I've changed the directive to apply the a new value back to the model when change event is triggered, so it will work as an input text.
.directive('ngUpdateHidden', function () {
return {
restrict: 'AE', //attribute or element
scope: {},
replace: true,
require: 'ngModel',
link: function ($scope, elem, attr, ngModel) {
$scope.$watch(ngModel, function (nv) {
elem.val(nv);
});
elem.change(function () { //bind the change event to hidden input
$scope.$apply(function () {
ngModel.$setViewValue( elem.val());
});
});
}
};
})
so when you trigger $("#yourInputHidden").trigger('change') event with jQuery, it will update the binded model as well.
Found a strange behaviour about this hidden value () and we can't make it to work.
After playing around we found the best way is just defined the value in controller itself after the form scope.
.controller('AddController', [$scope, $http, $state, $stateParams, function($scope, $http, $state, $stateParams) {
$scope.routineForm = {};
$scope.routineForm.hiddenfield1 = "whatever_value_you_pass_on";
$scope.sendData = function {
// JSON http post action to API
}
}])
I achieved this via -
<p style="display:none">{{user.role="store_user"}}</p>
update #tymeJV 's answer
eg:
<div style="display: none">
<input type="text" name='price' ng-model="price" ng-init="price = <%= #product.price.to_s %>" >
</div>
I had facing the same problem,
I really need to send a key from my jsp to java script,
It spend around 4h or more of my day to solve it.
I include this tag on my JavaScript/JSP:
$scope.sucessMessage = function (){
var message = ($scope.messages.sucess).format($scope.portfolio.name,$scope.portfolio.id);
$scope.inforMessage = message;
alert(message);
}
String.prototype.format = function() {
var formatted = this;
for( var arg in arguments ) {
formatted = formatted.replace("{" + arg + "}", arguments[arg]);
}
return formatted;
};
<!-- Messages definition -->
<input type="hidden" name="sucess" ng-init="messages.sucess='<fmt:message key='portfolio.create.sucessMessage' />'" >
<!-- Message showed affter insert -->
<div class="alert alert-info" ng-show="(inforMessage.length > 0)">
{{inforMessage}}
</div>
<!-- properties
portfolio.create.sucessMessage=Portf\u00f3lio {0} criado com sucesso! ID={1}. -->
The result was:
Portfólio 1 criado com sucesso! ID=3.
Best Regards
Just in case someone still struggles with this, I had similar problem when trying to keep track of user session/userid on multipage form
Ive fixed that by adding
.when("/q2/:uid" in the routing:
.when("/q2/:uid", {
templateUrl: "partials/q2.html",
controller: 'formController',
paramExample: uid
})
And added this as a hidden field to pass params between webform pages
<< input type="hidden" required ng-model="formData.userid" ng-init="formData.userid=uid" />
Im new to Angular so not sure its the best possible solution but it seems to work ok for me now
Directly assign the value to model in data-ng-value attribute.
Since Angular interpreter doesn't recognize hidden fields as part of ngModel.
<input type="hidden" name="pfuserid" data-ng-value="newPortfolio.UserId = data.Id"/>
I use a classical javascript to set value to hidden input
$scope.SetPersonValue = function (PersonValue)
{
document.getElementById('TypeOfPerson').value = PersonValue;
if (PersonValue != 'person')
{
document.getElementById('Discount').checked = false;
$scope.isCollapsed = true;
}
else
{
$scope.isCollapsed = false;
}
}
Below Code will work for this IFF it in the same order as its mentionened
make sure you order is type then name, ng-model ng-init, value. thats It.
Here I would like to share my working code :
<input type="text" name="someData" ng-model="data" ng-init="data=2" style="display: none;"/>
OR
<input type="hidden" name="someData" ng-model="data" ng-init="data=2"/>
OR
<input type="hidden" name="someData" ng-init="data=2"/>
Using the TokenInput plugin and using AngularJS built-in formController validation.
Right now I'm trying to check if the field contains text, and then set field to valid if it does. The issue with using the plugin is it creates it's own input and then a ul+li for stlying.
I have access to addItem (formname) and my capablities in the controller, I just need to set it to $valid.
Markup.
<form class="form-horizontal add-inventory-item" name="addItem">
<input id="capabilities" name="capabilities" token-input data-ng-model="inventoryCapabilitiesAutoComplete" data-on-add="addCapability()" data-on-delete="removeCapability()" required>
<div class="required" data-ng-show="addItem.capabilities.$error.required" title="Please enter capability."></div>
</form>
JS.
$scope.capabilityValidation = function (capability) {
if (capability.name !== "") {
addItem.capabilities.$valid = true;
addItem.capabilities.$error.required = false;
} else {
addItem.capabilities.$valid = false;
addItem.capabilities.$error.required = true;
}
};
I'm running the capabilityValidation function when TokenInput has something entered and passing in the object.
EDIT:
Found out ng-model on my input does stuff and gets the autocomplete results, which is why I can't get ng-valid to work since it's based on the model.
$scope.inventoryCapabilitiesAutoComplete = {
options: {
tokenLimit: null
},
source: urlHelper.getAutoComplete('capability')
};
I didn't write this autocomplete implementation, is there another way to do this where I would have access to the ng-model attr and move the model function somewhere else?
You cannot directly change a form's validity. If all the descendant inputs are valid, the form is valid, if not, then it is not.
What you should do is to set the validity of the input element. Like so;
addItem.capabilities.$setValidity("youAreFat", false);
Now the input (and so the form) is invalid.
You can also see which error causes invalidation.
addItem.capabilities.errors.youAreFat == true;
The answers above didn't help me solve my problem. After a long search I bumped into this partial solution.
I've finally solved my problem with this code to set the input field manually to ng-invalid (to set to ng-valid set it to 'true'):
$scope.myForm.inputName.$setValidity('required', false);
I came across this post w/a similar issue.
My fix was to add a hidden field to hold my invalid state for me.
<input type="hidden" ng-model="vm.application.isValid" required="" />
In my case I had a nullable bool which a person had to select one of two different buttons. if they answer yes, an entity is added to the collection and the state of the button changes. Until all of the questions get answered, (one of the buttons in each of the pairs has a click) the form is not valid.
vm.hasHighSchool = function (attended) {
vm.application.hasHighSchool = attended;
applicationSvc.addSchool(attended, 1, vm.application);
}
<input type="hidden" ng-model="vm.application.hasHighSchool" required="" />
<div class="row">
<div class="col-lg-3"><label>Did You Attend High School?</label><label class="required" ng-hide="vm.application.hasHighSchool != undefined">*</label></div>
<div class="col-lg-2">
<button value="Yes" title="Yes" ng-click="vm.hasHighSchool(true)" class="btn btn-default" ng-class="{'btn-success': vm.application.hasHighSchool == true}">Yes</button>
<button value="No" title="No" ng-click="vm.hasHighSchool(false)" class="btn btn-default" ng-class="{'btn-success': vm.application.hasHighSchool == false}">No</button>
</div>
</div>
It is very simple. For example :
in you JS controller use this:
$scope.inputngmodel.$valid = false;
or
$scope.inputngmodel.$invalid = true;
or
$scope.formname.inputngmodel.$valid = false;
or
$scope.formname.inputngmodel.$invalid = true;
All works for me for different requirement. Hit up if this solve your problem.
to get this working for a date error I had to delete the error first before calling $setValidity for the form to be marked valid.
delete currentmodal.form.$error.date;
currentmodal.form.$setValidity('myDate', true);