Angularjs how to user ng-default with ng-repeat - angularjs

I am having below data as input json,
"values":[
{"_attributes":{"name":"data.domain"},"_text":"${url}"},
{"_attributes":{"name":"data.port"}},
{"_attributes":{"name":"data.comments"},"_text":"Defaults Comments"},
{"_attributes":{"name":"data.concurrent"},"_text":4}]
]
I am showing comments in my html page using this directive,
<b style="padding-top:5px;"> Comments:</b>
<span class="input">
<input class="inputtxt" type="text" ng-repeat="x in ValueArr" ng-if="x._attributes.name == 'data.comments'" ng-model="x._text">
</span>
which is working fine and showing as expected. But the problem is that sometimes, the comments node
{"_attributes":{"name":"data.comments"},"_text":"Defaults Comments"},
may not be present in array. like this,
"values":[
{"_attributes":{"name":"data.domain"},"_text":"${url}"},
{"_attributes":{"name":"data.port"}},
{"_attributes":{"name":"data.concurrent"},"_text":4}]
]
In that case it shows only "Comments:" and blank screen after that. It does not show input box. In this case, I want to show empty input box. I tried ng-default and and ng-init but that didn't work. How to display input box for absence of matching condition ?
jsfiddle
Not getting any idea, how to achieve that. Please suggest something.
Thanks

The solution works with ng-init.
Just put it on the input like this:
<span class="input" ng-init="initValues()">
<input class="inputtxt" type="text" ng-repeat="x in values" ng-show="x._attributes.name == 'data.comments'" ng-model="x._text" ng-init="initInput(x)">
</span>
And add the function in the Controller:
$scope.initInputComments = function(x) {
if (!x._text || x._text == "") {
x._text = "Defaults Comments"
}
}
Note that you need to test that x._text exists/is defined.
$scope.initValues = function() {
var containsComment = false;
for (var i = 0; i < $scope.values.length; ++i) {
if ($scope.values[i]._attributes.name == 'data.comments') {
containsComment = true;
}
}
if (!containsComment) {
$scope.values.push({
"_attributes": {
"name": "data.comments"
}
});
}
}
Check the working fiddle

Related

How Can i do Only one checkbox selected at a time in given list in ngFor in angular 5?

I want to do only one checkbox selected at a time in ngFor in angular 5.
i have the following code below.
<div class="form-check" style="margin-top:0;">
<label class="form-check-label">
<input class="form-check-input" id="res{{restaurant._id}}" (change)="selectRestaurant(restaurant,i)" [checked]="restaurant.checked" type="checkbox">
<span class="form-check-sign"></span>
</label>
</div>
And in my component
selectRestaurant(restaurant: any, i: any) {
if (restaurant) {
restaurant.checked = !restaurant.checked;
}
}
So any possible solution for only one checkbox selected in given list?
You have to bind the checkbox item with ngmodel to the specific instance in for loop.
This you can try with ReactiveForms. See one example https://stackblitz.com/angular/ayqnbvbkmpy
I saw many examples with loop using. But I`am think its bad idea when checkboxes are too many. I recommend to use another way.
Create variable to contain checkbox index.
public checkboxIndex = 0; //default value for checking
public checkboxModel = [];
ngOnInit() {
for (let i = 0; i < checkboxCount.length; i++) {
this.checkboxModel.push({ name: `${i}`, enabled: false });
}
public checkboxChange(index) {
if (this.checkboxIndex !== index) {
this.checkboxModel[this.checkboxIndex].enabled = false;
}
this.checkboxIndex = index;
}
//HTML
<div *ngFor="let checkbox of checkboxCount.length; let i = index">
<input type="checkbox" [(ngModel)]="checkboxModel[i].enabled"
name="checkboxModel[i].name"
(change)="checkboxChange(i)"> </input>
</div>
It should help. Please correct me if I made some mistakes.

Remove empty option in the select using ng-model

I am new to angular js. In my code user changes the value of radio buttons. And depending on the value of the selected radio button, a piece of code is loaded from the ng-switch
HTML:
<body ng-app="">
<div ng-repeat="button in modes">
<label>
<input type="radio" ng-model="data.mode" value="{{button.value}}" ng-click="clearObjectIdModal()" name="e_modes">
{button.label}}
</label>
</div>
<div ng-switch on="data.mode">
<div ng-switch-when="client">
<label for="e_selected_object_item_id">Select Client name: </label>
<select id="e_selected_object_item_id" name="e_selected_object_item_id" ng-model="currentDataItem.object_id" required>
<option ng-repeat="item in customersListArr" value="{{ item.id }}">{{ item.Name }}</option>
</select>
</div>
<div ng-switch-when="agent">
// This part is similar to the previous one
</div>
</div>
</body>
Controller part:
$scope.data = {};
$scope.setFile = function () {
if ($scope.data.mode == 'client')
return 'client';
else if ($scope.data.mode == 'agent')
return 'agent';
$scope.modes = [{
value: 'client',
label: 'Client'
},{
value: 'agent',
label: 'Agent'
}];
$scope.currentDataItem = data; // data is preloaded from inputs in form
There is also a ng-click="clearObjectIdModal()" that clears the model when switching radio buttons:
$scope.clearObjectIdModal = function() {
$scope.currentDataItem = "";
}
The problem is that every time when the radio button is switched to the select value, which dynamically changes, the value of the first option in it becomes equal to undefined. Because in the array from where these options are built there is no such object_id (This is the id that is not there, so an empty field is drawn).
That is, there are all works. But the first option in the select(after switching to another radio button) is rendered as an empty string.
There are thoughts, how it can be fixed?
I'm not sure if I understand you problem correctly but I would suggest a few improvements.
change your setFile function to as follows
$scope.setFile = function (){return $scope.data.mode;}
I also do not see the closing brackets for your function in your code. Besides if your function will only return the data.mode then why need the function?
I would suggest initialize your data object properly like:
$scope.data = {mode:'client'};
Change your clearObjectIdModal function as:
$scope.clearObjectIdModal = function(mode)
{
$scope.currentDataItem = "";
$scope.data.mode=mode;
}
and in your HTML use it as ng-click="clearObjectIdModal(button.mode)"
So in function clearObjectIdModal() I wrote:
$scope.clearObjectIdModal = function() {
if ($scope.e_data["mode"] == 'client') {
if ($scope.customersListArr.length > 0) {
$scope.currentDataItem.object_id = $scope.customersListArr[0]['id'];
}
}
else if ($scope.e_data["mode"] == 'agent') {
if ($scope.agentsListArr.length > 0) {
$scope.currentDataItem.object_id = $scope.agentsListArr[0]['id'];
}
}
}
And after this when I change radio buttons the first option in current select(which every time is changed) will be not empty.
Also the problem with an additional empty option is possible to solve when you add a title as the first item in the list:
<option value="" disabled>Select</option>

Trying to validate that at least one checkbox is checked angularJS

Trying to figure out the best way to stay on the same page alerting the user if they have failed to check at least one checkbox.
HTML:
<div class="col3">
<input type="checkbox" ng-model="$parent.value5" ng-true-value="'Togetherness'" ng-false-value="">
<span class="checkboxtext">
Togetherness
</span><br>
<!--<p>We value our people and recognize that <strong>Together</strong> we achieve superior results.</p><br>-->
<div class="col3">
<a ui-sref="form.submit">
<button name="button" ng-click="SaveValue()">Continue</button>
</a>
Back-end angularJS to check if one of the boxes was checked-
$scope.SaveValue = function () {
var valueStatus = [];
if ($scope.value1 === "Methodical")
{
valueStatus.push($scope.value1);
}
if ($scope.value2 === "Relentless")
{
valueStatus.push($scope.value2);
}
if ($scope.value3 === "Togetherness")
{
valueStatus.push($scope.value3)
}
if ($scope.value4 === "Excellent") {
valueStatus.push($scope.value4)
}
if ($scope.value5 === "Ingenious") {
valueStatus.push($scope.value5)
}
return valueStatus
};
Basically I'm wanting to make an array of these values and then return it. However, I want the user to check at least one box. I've tried redirecting back to the page if valueStatus[0] == null. However, I don't think this is the best way to validate and it does not work completely how I think it ought to.
The way I solve this is putting validation on the length of array (valueStatus in your case) with hidden number input. The input will have min validation on. So, if user fails to check at least one, the form is not submitted;
<input type="number" name="valueStatus" ng-model="valueStatus.length" min="1" style="display: none">
Then, you can use normal validation on valueStatus that is available on the form model
myFormName.valueStatus.$valid
This way, most of the logic is put into the template, which is called angularjs way ;)
UPDATE
Forgot to mention:
You need to update the list of checked values on on-change checkbox event
<input type="checkbox" ng-model="checkboxValue1" on-change="updateValueStatus(checkboxValue1)">
<input type="checkbox" ng-model="checkboxValue2" on-change="updateValueStatus(checkboxValue2)">
and in controller
$scope.updateValueStatus = function(value){
var indexOf = $scope.valueStatus.indexOf(value);
if(indexOf < 0) {
$scope.valueStatus.push(value);
} else {
$scope.valueStatus.splice(indexOf, 1);
}
}
Hope it will help people with the same issue
simply just check the valueStatus length is equal to 0 or not
$scope.SaveValue = function () {
var valueStatus = [];
if ($scope.value1 === "Methodical")
{
valueStatus.push($scope.value1);
}
if ($scope.value2 === "Relentless")
{
valueStatus.push($scope.value2);
}
if ($scope.value3 === "Togetherness")
{
valueStatus.push($scope.value3)
}
if ($scope.value4 === "Excellent") {
valueStatus.push($scope.value4)
}
if ($scope.value5 === "Ingenious") {
valueStatus.push($scope.value5)
}
if (valueStatus.length === 0 ) {
console.log('please select atleast one select box')
}
return valueStatus
};
Edited
remove the ui-sref tag and change the state inside your click function
<button name="button" ng-click="SaveValue()">Continue</button>
in the saveValue function add this
if (valueStatus.length === 0 ) {
console.log('please select atleast one select box')
}else{
$state.go('form.submit') // if atleast one selected then the page will change
}

Angular Xeditable drop down e-ng-change is not working

I'm using Angular Xeditable api.I need to change the text field's value according to the value of the drop down.But it's not working.Could you tell me why ? Thanks.
Html
<td>
<span editable-select="user.status" e-form="tableform" e-ng-options="s.value as s.text for s in statuses" e-ng-change="setName($data,user)">
{{ showStatus(user) }}
</span>
</td>
js
$scope.setName = function (id, user) {
var selected = [];
if (id) {
selected = $filter('filter')($scope.statuses, { value: id });
}
if (selected.length) {
user.name = selected[0].text;
}
};
Generated html : you can see that it has been changed text of the name filed as expected (status3).But it doesn't update the text box properly. In other words it doesn't show on the text box.Why ?
<td>
<!-- editable username (text with validation) -->
<span editable-text="user.name" e-form="tableform" onbeforesave="checkName($data, user.id)" class="ng-scope ng-binding editable editable-hide">
status3
</span><span class="editable-wrap editable-text ng-scope"><div class="editable-controls form-group" ng-class="{'has-error': $error}"><input type="text" class="editable-input form-control ng-pristine ng-valid" ng-model="$data"><div class="editable-error help-block ng-binding" ng-show="$error" ng-bind="$error" style="display: none;"></div></div></span>
</td>
UPDATE :
I have tried like this.But then it changes all the rows values.So how can I detect only the changed row ?
$scope.setName = function (id, user,form) {
var selected = [];
if (id) {
selected = $filter('filter')($scope.statuses, { value: id });
}
if (selected.length) {
for (var i = 0; i < form.$editables.length; i++) {
if (form.$editables[i].name === 'user.name') {
form.$editables[i].scope.$data ="sampath"
}
}
}
};
Here is the JsFiddle
I try with your old source code and it's works for me:
if (selected.length) {
user.name = selected[0].text;
}
May be i miss understand your problem.
http://jsfiddle.net/NfPcH/14573/
If I understand it right, you just want to update the text on the textbox (which is bound to the user's name) depending on the status change, right?
If so, then your UPDATED code is too complicated. Just update the property directly on the user object passed to the setName function (like in your first example). It is already bound to the textbox, so you don't have to go all the way around and update the textbox directly. That's the whole point of using angular. You update the models on the scope and the rest happens automatically.
$scope.setName = function (id, user) {
if (!id || !user) {
// Do something to handle this...
return;
}
var selected = $filter('filter')($scope.statuses, { value: id });
selected = selected.length ? selected[0] : null;
user.name = 'sampath (' + selected.text + ')';
};
Here is an udpated fiddle:
http://jsfiddle.net/NfPcH/14765/

AngularJS: list all form errors

Background:
I am currently working on an application with tabs; and I'd like to list the fields / sections that fail validation, to direct the user to look for errors in the right tab.
So I tried to leverage form.$error to do so; yet I don't fully get it working.
If validation errors occur inside a ng-repeat, e.g.:
<div ng-repeat="url in urls" ng-form="form">
<input name="inumber" required ng-model="url" />
<br />
</div>
Empty values result in form.$error containing the following:
{ "required": [
{
"inumber": {}
},
{
"inumber": {}
}
] }
On the other hand, if validation errors occur outside this ng-repeat:
<input ng-model="name" name="iname" required="true" />
The form.$error object contains the following:
{ "required": [ {} ] }
yet, I'd expect the following:
{ "required": [ {'iname': {} } ] }
Any ideas on why the name of the element is missing?
A running plunkr can be found here:
http://plnkr.co/x6wQMp
As #c0bra pointed out in the comments the form.$error object is populated, it just doesn't like being dumped out as JSON.
Looping through form.$errors and it's nested objects will get the desired result however.
<ul>
<li ng-repeat="(key, errors) in form.$error track by $index"> <strong>{{ key }}</strong> errors
<ul>
<li ng-repeat="e in errors">{{ e.$name }} has an error: <strong>{{ key }}</strong>.</li>
</ul>
</li>
</ul>
All the credit goes to c0bra on this.
Another option is to use one of the solutions from this question to assign unique names to the dynamically created inputs.
I made a function that you pass the form to. If there are form errors it will display them in the console. It shows the objects so you can take a look. I put this in my save function.
function formErrors(form){
var errors = [];
for(var key in form.$error){
errors.push(key + "=" + form.$error);
}
if(errors.length > 0){
console.log("Form Has Errors");
console.log(form.$error);
}
};
Brett DeWoody's answer is correct. I wanted to do the logic in my controller though. So I wrote the below, which is based off of the answer user5045936 gave. This may also help some of you who want to go the controller route. By the way Im using the toaster directive to show my users validation messages.
if (!vm.myForm.$valid) {
var errors = [];
for (var key in vm.myForm.$error) {
for (var index = 0; index < vm.myForm.$error[key].length; index++) {
errors.push(vm.myForm.$error[key][index].$name + ' is required.');
}
}
toaster.pop('warning', 'Information Missing', 'The ' + errors[0]);
return;
}
If you have nested forms then you will find this helpful:
function touchErrorFields(form) {
angular.forEach(form.$error, function (field) {
angular.forEach(field, function(errorField) {
if (!errorField.hasOwnProperty('$setTouched')) {
touchErrorFields(errorField);
} else {
errorField.$setTouched();
}
})
});
}

Resources