AngularJS. Dynamically added inputs don't affect $valid - angularjs

trying to make a dynamically composed form.
Fields and attributes come from server. Angular should get them and generate a form.
I decided to use directive and runtime compilation.
Mostly all works except a few things.
The problem: $valid is undefined for compiled fields.
For static fields is works.
Please give me an advice.
app = angular.module('dyno', []);
app.controller("fieldCompilation", function($scope) {
$scope.list = [{
id: "0",
name: "A"
},
{
id: "1",
name: "B"
},
{
id: "2",
name: "C"
},
];
});
app.directive("otcDynamic", function($compile) {
return {
link: function(scope, element) {
// Add Text Input with pattern validation and required attr
var template = "<input type='text' name='input3' ng-model='input3' placeholder='input3 [0-9]{2} required' pattern='[0-9]{2}' required='true'/>";
var linkFn = $compile(template);
var content = linkFn(scope);
angular.element(document.getElementById("f3")).append(content);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.2/angular.min.js"></script>
<div ng-app="dyno">
<div ng-controller="fieldCompilation">
<br><b> Static Input:</b>
<ng-form name="form1">
<div id="f1">
1. Input <input type='text' name='input1' ng-model='input1' placeholder='input1 [0-9]{2} required' pattern='[0-9]{2}' required='true' /><br>
</div>
<br><b> Dynamic Inputs:</b>
<div otc-dynamic>
<div id="f3">
3. Input
</div>
</div>
<br> <b>Details</b>
<div>
Counter: {{ message }}
</div>
<div>
Model Input1: {{ input1 }}
</div>
<div>
Model input3: {{ input3 }}
</div>
<div>
Validation input1: {{ form1.input1.$valid }}<br> Validation input3: {{ form1.input3.$valid }}<br> Validation form1: {{ form1.$valid }}<br>
</div>
</ng-form>
</div>
</div>
Fiddle

Related

Is there a property in angularjs form to get only the changed values?

I'm trying to submit only the user modified data in an Angular Js form. How do we do it in Angular Js? (Version: 1.4.14).
I've come across the property $$success.parse of form. But there is no details about this property in Angular Js website. Can we use this property? Any help is appreciated.
As stated in comments, you want to check $dirty property of each form element.
See example here https://next.plnkr.co/edit/YW7ad8vYjfE9jnLW?preview
HTML
<body ng-controller="MainCtrl" ng-cloak>
<form name="userForm">
<div>
Name:
<input
name="name"
type="text"
ng-model="user.name"
ng-change="getChanges(userForm)">
Age:
<input
name="age"
type="number"
ng-model="user.age"
ng-change="getChanges(userForm)">
Gender:
<select
name="gender"
ng-model="user.gender"
ng-change="getChanges(userForm)">
<option value="M">M</option>
<option value="F">F</option>
<option value="O">Other</option>
</select>
</div>
<div>
<button
name="reset"
type="button"
ng-click="setPristine(userForm)">Set pristine
</button>
</div>
</form>
<div>
User changed values: {{ changedValues | json }}
</div>
</body>
JavaScript
angular.module('app', []).controller('MainCtrl', function($scope, $timeout) {
angular.extend($scope, {
user: {
name: null,
age: null,
gender: null
},
changedValues: {},
getChanges: function(form) {
$scope.changedValues = {};
angular.forEach(form, function(value, key) {
if (!key.startsWith('$')) {
if (value.$dirty) {
$scope.changedValues[key] = value.$modelValue;
}
}
});
},
setPristine: function(form) {
form.$setPristine();
$scope.getChanges(form);
}
});
$timeout($scope.reset);
});

ng-dialog: input radio button value is undefined

I'm trying to get the radio value button value from ng-dialog but it always got undefined.
Here is the dialog template:
<script type="text/ng-template" id="flag-reasons.html">
<div style="padding:10px;">
<span>
What's wrong ?
</span>
<div class="form-group" ng-repeat="flagreason in flagreasons">
<input type="radio" ng-model="fr" name="frname" value="{{flagreason.id}}"> {{flagreason.title}}
</div>
<div class="form-group">
<button type="button" ng-click="validFlag()">
Valider
</button>
</div>
</div>
</script>
Here is the partial js where I start with the dialog:
$scope.openFlag = function(){
$scope.dialog = ngDialog.open({ template: 'flag-reasons.html',
className: 'ngdialog-theme-default', scope: $scope });
$scope.validFlag = function(){
console.log($scope.fr);
}
}
I have tried ng-value as below:
<input type="radio" ng-model="fr" name="frname" ng-value="flagreason.id"> {{flagreason.title}}
but it still got undefined
Notice that it works when I directly set the value of the radio button like:
<input type="radio" ng-model="fr" name="frname" value="5"> {{flagreason.title}}
The issue is with ngmodel that's not getting update. You have to initialise ngmodel first in the template.
flag-reasons.html
<script type="text/ng-template" id="flag-reasons.html">
<div style="padding:10px;">
<span>
What's wrong ?
</span>
<div class="form-group" ng-repeat="flagreason in flagreasons">
<input type="radio" ng-model="cb.fr" name="frname" value="{{flagreason.id}}">{{flagreason.id}} - {{flagreason.title}}
</div>
<div class="form-group">
<button type="button" ng-click="validFlag()">
Valider
</button>
</div>
</div>
</script>
Controller
angular.module("app", ['ngDialog'])
.controller('Ctrl',function ($scope, ngDialog) {
'use strict';
$scope.cb = {};
$scope.flagreasons = [
{id: 1, title: 'title1'},
{id: 2, title: 'title2'},
{id: 3, title: 'title3'}
];
$scope.openFlag = function(){
$scope.dialog = ngDialog.open({ template: 'flag-reasons.html',
className: 'ngdialog-theme-default', scope: $scope });
$scope.validFlag = function(){
console.log($scope.fr);
}
}
$scope.$watch('cb.fr', function (v) {
console.log(v);
});
});
Working Fiddle: JSFiddle

Kendo MultiSelect update of ngmodel

I'm trying to add one button for adding values to ngmodel of kendo's multi select:
<div ng-controller="MyCtrl">
<select id='my' kendo-multi-select k-options="selectOptions" k-ng-model="selectedIds"></select>
<p ng-show="selectedIds.length">Selected: {{ selectedIds }}</p>
<button ng-click="addSelectedId()">Add selected id</button>
<input ng-model="enteredId" />
</div>
Here is controller
function MyCtrl($scope) {
$scope.selectOptions = {
placeholder: "Select products...",
dataTextField: "ProductName",
dataValueField: "ProductID",
autoBind: false,
dataSource: {
type: "odata",
serverFiltering: true,
transport: {
read: {
url: "http://demos.telerik.com/kendo-ui/service/Northwind.svc/Products",
}
}
}
};
$scope.selectedIds = [ 4, 7];
$scope.addSelectedId = function() {
$scope.selectedIds.push(parseInt($scope.enteredId));
console.log($scope.selectedIds);
};
}
Plunker is here:
http://plnkr.co/edit/EH0EaMhFsV2JTdwpkqGg?p=preview
When added to selectedIds, nothing gets added to dropdown select placeholder. Any ideas?
You need to add k-rebind="selectedIds" in your html code
HTML:
<div ng-controller="MyCtrl">
<select id='my' kendo-multi-select k-options="selectOptions" k-ng-model="selectedIds" k-rebind="selectedIds"></select>
<p ng-show="selectedIds.length">Selected: {{ selectedIds }}</p>
<button ng-click="addSelectedId()">Add selected id</button>
<input ng-model="enteredId" />
</div>
Please see this updated plunker example

how to show/hide div according to user permission/role using angularjs in sharepoint 2010

i have to create a form using content editor web part in SharePoint 2010. I have to hide some item or div based on group permission (example: admin,user) using angularjs.
There have two ways to solve your problem:
You receive all the data and you display it or not based on the current role, helped by a display function. jsFiddle1
Javascript code:
var demoApp = angular.module('demoApp', []);
demoApp.controller('PermissionsForm', function ($scope) {
// Mock data. You must receive it from your server
$scope.mockData = {
field1: {
value: 'field1 value',
roles: ['admin','user']
},
field2: {
value: 'field2 value',
roles: ['admin']
},
field3: {
value: 'field3 value',
roles: ['admin','user']
},
role: 'user'
};
$scope.displayField = function(fieldName){
var foundRole = false;
angular.forEach($scope.mockData[fieldName].roles, function(value, key) {
if (value == $scope.mockData.role){
foundRole = true;
}
});
return foundRole;
};
});
HTML code:
<div data-ng-app="demoApp" data-ng-controller="PermissionsForm" class="main">
<form>
<div ng-if="displayField('field1')">
<label for="field1">Field 1</label>
<input id="field1" value="{{mockData.field1.value}}">
</div>
<div ng-if="displayField('field2')">
<label for="field2">Field 2</label>
<input id="field2"value="{{mockData.field2.value}}">
</div>
<div ng-if="displayField('field3')">
<label for="field3">Field 3</label>
<input id="field3" value="{{mockData.field3.value}}">
</div>
</form>
</div>
You receive only the data related to each roles/permission and you build your interface with the list of fields. This is the more secure way to hide info. jsFiddle2
Javascript code:
var demoApp = angular.module('demoApp', []);
demoApp.controller('PermissionsForm', function ($scope) {
// Mock data. You must receive it from your server
$scope.mockData = {
field1: {
value: 'field1 value'
},
field3: {
value: 'field3 value'
},
field4: {
value: 'field4 value'
}
};
$scope.displayField = function(fieldName){
if ( $scope.mockData[fieldName] == undefined )
return false;
return true;
};
});
HTML code:
<div data-ng-app="demoApp" data-ng-controller="PermissionsForm" class="main">
<form>
<div ng-if="displayField('field1')">
<label for="field1">Field 1</label>
<input id="field1" value="{{mockData.field1.value}}">
</div>
<div ng-if="displayField('field2')">
<label for="field2">Field 2</label>
<input id="field2"value="{{mockData.field2.value}}">
</div>
<div ng-if="displayField('field3')">
<label for="field3">Field 3</label>
<input id="field3" value="{{mockData.field3.value}}">
</div>
<div ng-if="displayField('field4')">
<label for="field4">Field 4</label>
<input id="field4" value="{{mockData.field4.value}}">
</div>
</form>
</div>
From a secure point of view, the second solution is the best, because your are not exposing the data in the client side (browser)

list not displaying in angular binding?

I am trying my first angular js list example. Having issues displaying the list, there are no errors in the console:(
html
<body ng-controller="mycontroller">
<form ng-submit="addtask()">total nr of tasks: {{myvar.length}}
<br />remaining: {{remaining()}}
<input type="text" ng-model="newtask" />
<ul ng-repeat="var in myvar">
<li>
<input type="checkbox" ng-model="myvardone" /> <span class="done-{{myvardone}}">{{var.text}}</span>
</li>
</ul>
<button type="submit">add</button>
</form>
</body>
script:
function mycontroller($scope) {
$scope.myvar = [{
text: 'bert',
done: false
}, {
text: 'ed',
done: true
}, {
text: 'pet',
done: false
}];
$scope.addtask = function () {
$scope.myvar.push({
text: $scope.newtask,
done: false
});
}
$scope.remaining = function () {
var count = 0;
angular.forEach($scope.myvar, function (t) {
if (t.done) {
count++
} else {
count += 0;
}
});
return count;
}
}
jsfiddle:http://jsfiddle.net/dingen2010/vc2bC/3/
simple demo can be like
<html ng-app>xxxxx</html>
don't forget "ng-app"
Several things
One. missed ng-app
Two. You should not repeating ul, but li
<li ng-repeat="var in myvar">
<input type="checkbox" ng-model="var.done" />
<span class="done-{{var.done}}">{{var.text}}</span>
</li>
Three. when you add, you need to have task name entered.
Four, you don't need remaining function. use filter
{{ (myvar | filter:{done:true}).length }}
http://jsfiddle.net/vc2bC/10/
Darn, Awakening beat me to it... :/ But yeah, just simply move the ng-controller tag to a containing and put a ng-app tag on the html tag. Here:
enter code herehttp://jsfiddle.net/vc2bC/8/

Resources