HTML form is not generated in angular scope - angularjs

I am trying to generate a HTML form with angularjs ngRepeat. I load a JSON file that contains the fields of desired form and save this object in my $scope. I have a ngRepeat element that generates form inputs based on the JSON object.
The problem is when I print $scope.<myFormName> it just have one field name "{{header.name}}" as I expect some fields based on my JSON model.
Actually I see the form generated in HTML properly but the same thing does not happen in angular scope.
angular.module("myApp",[])
.controller("myCtrl",["$scope",function($scope){
// In this funtion I Set fields of form and make my model empty
$scope.getHeaders = function () {
console.info('getHeaders');
$scope.headersForCreation = [
{
name: 'givenName',
type: 'string',
caption: "nameAndFamily"
},
{
name: 'userName',
type: 'string',
caption: "userName"
},
{
name: 'password',
type: 'password',
caption: "password"
},
{
name: 'passwordConfirm',
type: 'password',
caption: "passwordConfirm"
},
{
name: 'mail',
type: 'string',
caption: "email"
},
{
name: 'mobile',
type: 'string',
caption: "mobile",
regex: '0[1-9][0-9]{9}'
}
];
$scope.userInputsInCreation = {};
angular.forEach($scope.headersForCreation, function (headerItem, key) {
$scope.userInputsInCreation[headerItem.name] = '';
});
}; // end of get header
$scope.getHeaders();
console.log($scope.createForm)
}])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl" id="add-container-access" ng->
<form class="form-horizontal" name="createForm" init="getHeaders()">
<div class="form-group" ng-repeat="header in headersForCreation" >
<label for="id-{{header.name}}" class="col-sm-4 control-label">
{{header.caption}}: </label>
<div class="col-sm-8"
ng-class="{'has-error': createForm.{{header.name}}.$error.$invalid }">
<input type="header.type" class="form-control"
name="{{header.name}}" ng-required="{{header.notNull}}"
id="id-{{header.name}}"
ng-model="userInputsInCreation[header.name]" >
</div>
</div>
<div class="form-group">
<div class="col-sm-2">
<button class="btn btn-default" >
ADD
<i class="glyphicon glyphicon-plus-sign"></i>
</button>
</div>
</div>
</form>
</div>

Because your controller initialized before AngularJS form directive.
angular.module("myApp",[])
.controller("myCtrl",["$scope","$timeout",function($scope, $timeout){
// In this funtion I Set fields of form and make my model empty
$scope.getHeaders = function () {
console.info('getHeaders');
$scope.headersForCreation = [
{
name: 'givenName',
type: 'string',
caption: "nameAndFamily"
},
{
name: 'userName',
type: 'string',
caption: "userName"
},
{
name: 'password',
type: 'password',
caption: "password"
},
{
name: 'passwordConfirm',
type: 'password',
caption: "passwordConfirm"
},
{
name: 'mail',
type: 'string',
caption: "email"
},
{
name: 'mobile',
type: 'string',
caption: "mobile",
regex: '0[1-9][0-9]{9}'
}
];
$scope.userInputsInCreation = {};
angular.forEach($scope.headersForCreation, function (headerItem, key) {
$scope.userInputsInCreation[headerItem.name] = '';
});
}; // end of get header
$scope.getHeaders();
$timeout(function(){ console.log($scope.createForm); });
}])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl" id="add-container-access" ng->
<form class="form-horizontal" name="createForm" init="getHeaders()">
<div class="form-group" ng-repeat="header in headersForCreation" >
<label for="id-{{header.name}}" class="col-sm-4 control-label">
{{header.caption}}: </label>
<div class="col-sm-8"
ng-class="{'has-error': createForm.{{header.name}}.$error.$invalid }">
<input type="header.type" class="form-control"
name="{{header.name}}" ng-required="{{header.notNull}}"
id="id-{{header.name}}"
ng-model="userInputsInCreation[header.name]" >
</div>
</div>
<div class="form-group">
<div class="col-sm-2">
<button class="btn btn-default" >
ADD
<i class="glyphicon glyphicon-plus-sign"></i>
</button>
</div>
</div>
</form>
</div>

Related

AngularJS Email Validation

I am trying to show Email valid messages using below code but problem is email error message not showing in red color. How can I resolve this problem?
https://codepen.io/rama-krishna-the-selector/pen/PXOwQp?editors=1010
.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">
<!-- JAVA SCRIPT REFERENCES -->
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
<script src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="plunker" >
<div ng-controller="DynamicFormController">
<h3>Dynamic Radio Buttons</h3>
<form name="myForm" class="form-horizontal" role="form" ng-submit="submitForm()">
<div ng-repeat="field in entity.fields">
<ng-form name="form">
<!-- EMAIL FIELDS -->
<div ng-if="field.type=='email'" class="form-group" ng-class="{ 'has-error' :
form[field.name].$dirty && form[field.name].$error.required,
'has-success': form[field.name].$valid}">
<label class="col-sm-2 control-label">{{field.label}}</label>
<div class="col-sm-6">
<input type="{{ field.type }}" dynamic-name="field.name" id="{{field.name}}" ng-model="field.data"
class="form-control" required />
<p class="help-block" ng-show="form[field.name].$dirty && form[field.name].$error.required">{{field.name}}
is required</p>
<p class="help-block" ng-show="form[field.name].$dirty && form[field.name].$error.email">Please enter valid {{field.name}}</p>
<!-- <p class="help-block" ng-show="{{'form.'+field.name+'.$dirty && form.'+field.name+'.$error.required'}}">required</p> -->
</div>
</div>
</ng-form>
</div>
<br/>
<button ng-disabled="myForm.$invalid" type="submit" id="submit">Submit</button>
<br/>
<pre>{{entity|json}}</pre>
<br/>
</form>
</div>
</body>
</html>
.js
var app = angular.module('plunker',[]);
app.controller('DynamicFormController', function ($scope, $log) {
// we would get this from the api
$scope.entity = {
name : "Course",
fields :
[
{type: "text", name: "firstname", label: "Name" , required: true, data:""},
{type: "radio", name: "color_id", label: "Colors" , options:[{id: 1, name: "orange"},{id: 2, name: "pink"},{id: 3, name: "gray"},{id: 4, name: "cyan"}], required: true, data:""},
{type: "email", name: "emailUser", label: "Email" , required: true, data:""},
{type: "text", name: "city", label: "City" , required: true, data:""},
{type: "password", name: "pass", label: "Password" , min: 6, max:20, required: true, data:""},
{type: "select", name: "teacher_id", label: "Teacher" , options:[{name: "Mark"},{name: "Claire"},{name: "Daniel"},{name: "Gary"}], required: true, data:""},
{type: "checkbox", name: "car_id", label: "Cars" , options:[{id: 1, name: "bmw"},{id: 2, name: "audi"},{id: 3, name: "porche"},{id: 4, name: "jaguar"}], required: true, data:""}
]
};
$scope.submitForm = function(){
$log.debug($scope.entity);
}
})
.directive("dynamicName",function($compile){
return {
restrict:"A",
terminal:true,
priority:1000,
link:function(scope,element,attrs){
element.attr('name', scope.$eval(attrs.dynamicName));
element.removeAttr("dynamic-name");
$compile(element)(scope);
}
}
})
Well you can add a class like this:
ng-class="{'has-error': form[field.name].$error.email }"
So your element will change to :
<p class="help-block has-error" ng-class="{'has-error': form[field.name].$error.email }" ng-show="form[field.name].$dirty && form[field.name].$error.email">Please enter valid {{field.name}}</p>
And to your classes you can add a error class like this:
.has-error
{
color:red !important;
}
Update HTML with following directive with condition in tag at message Please enter valid {{field.name}}
ng-class="{'red':form[field.name].$error.email}"
add CSS class
.red{color:#ff0000;}
!important is not required in this case

How to get value of selected radio button

I am trying to get selected radio button value using below code but i am getting undefined value. what is my mistake?
html
<form name="form" class="form-horizontal" role="form">
<!-- RADIO BUTTONS -->
<div class="form-group">
<label class="col-sm-2 control-label">Clouds</label>
<div class="col-sm-6">
<label class="radio-inline" ng-repeat="option in entity.fields">
<input type="radio" ng-model="data" name="option.name" value="{{option.id}}">
{{option.name}}
</label>
</div>
</div>
<br />
<button type="submit" id="submit" ng-click="save(data)">Submit</button>
<br />
</form>
controller
routerApp.controller('DynamicController2', ['$scope', function ($scope) {
// we would get this from the api
$scope.entity = {
name: "my favorite fruits",
fields:
[{ id: 1, name: "orange" }, { id: 2, name: "pink" }, { id: 3, name: "gray" }, { id: 4, name: "cyan" }]
};
$scope.save = function (data) {
alert(data);
}
}]);
The variable 'data' used in ng-modal is not defined in the controller. You need to define 'data' variable as $scope. Then there's no need to pass the variable to the function save.
here how your controller should be
routerApp.controller('DynamicController2', ['$scope', function ($scope) {
// we would get this from the api
$scope.data;
$scope.entity = {
name: "my favorite fruits",
fields:
[{ id: 1, name: "orange" }, { id: 2, name: "pink" }, { id: 3, name: "gray" }, { id: 4, name: "cyan" }]
};
$scope.save = function () {
alert($scope.data);
}
}]);
And your button in html should be like :
<button type="submit" id="submit" ng-click="save()">Submit</button>
Hopefully this will solve your problem.

Adding the input fields dynamically from nested json object in angulajs

var inputs={
'firstname': '',
'lastName':'',
'account':{
'role':'',
'status':''
}
}
This is my model array. I want to display it dynamically in Webpage and by modifying the json array the changes should affect the form too.
Here is the image
UPD:
for your situation, you can use ng-switch to generate elements according to conditions.
Notice(already included in the code snippet):
ng-repeat will generate it's own scope, so your model won't update unless you bind it with the original scope. ref here.
OLD ANSWER:
use ng-model to implement two-way-databinding.
refer the code snippet below:
angular.module("app", []).controller("myCtrl", function($scope) {
$scope.inputs = {
'firstname': 'test first name',
'lastName': 'test last name',
'account': {
'role': 'test role',
'status': 'test status'
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.4/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
<!-- First Name: <input type="text" ng-model="inputs.firstname"><br>
Last Name: <input type="text" ng-model="inputs.lastName"><br> Account Role: <input type="text" ng-model="inputs.account.role"><br>
Account Status: <input type="text" ng-model="inputs.account.status"><br> -->
<div ng-repeat="(key1, value) in inputs" ng-switch="key1">
<div ng-switch-when="account">
<div ng-repeat="(key2, value2) in value">
{{key1 | uppercase}} => {{ key2 | uppercase}}
<input type="text" ng-model="inputs[key1][key2]">
</div>
</div>
<div ng-switch-default>
{{key1 | uppercase}}
<input type="text" ng-model="inputs[key1]">
</div>
</div>
{{inputs}}
</div>
/My html should look like this/
<head>
<script data-require="angular.js#1.4.1" data-semver="1.4.1" src="https://code.angularjs.org/1.4.1/angular.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="MainCtrl">
<script type="text/ng-template" id="tree-structure">
<label>{{dt}}</label><input type="text" name="" value="{{dt.label}}">
<ul class="childElement">
<li ng-repeat="dt in dt.nodes" ng-include="'tree-structure'">
</li>
</ul>
</script>
<ul class="parentList">
<li ng-repeat="(key, value) in inputs" >
<div ng-repeat="(key1, value1) in value">
<label>{{key1}}</label>
<input type="text" name="" value="{{value1}}">
<!-- <div ng-repeat="(key2, value2) in value1">
<label>{{key2}}</label><input type="text" name="" value="{{value2}}">
</div> -->
</div>
<div ></div>
</li>
</div>
</ul>
</body>
</html>
Some observations :
Your JSON should be formatted properly with type of the field.
If you want to access the object properties as a form fields then it should be structured in a good way so that we can dynamically add the type of the field as well.
[{
name: 'firstName',
type: 'text'
}, {
name: 'lastname',
type: 'text'
}, {
account: [{
name: 'role',
type: 'text'
}, {
name: 'status',
type: 'text'
}]
}]
As your JSON have nested objects. So, first iterate it recursively and create one dimensional array then create the fields using 1D array.
DEMO
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function($scope) {
var inputs = [{
name: 'firstName',
type: 'text'
}, {
name: 'lastname',
type: 'text'
}, {
account: [{
name: 'role',
type: 'text'
}, {
name: 'status',
type: 'text'
}]
}];
$scope.fields = [];
function structuredObj(obj) {
for (var i in obj) {
if (obj[i].type == 'text') {
$scope.fields.push(obj[i]);
} else {
structuredObj(obj[i])
}
}
};
structuredObj(inputs);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<form name="myForm" novalidate>
<div ng-repeat="item in fields" class="form-group">
<input
name="item.name"
type="{{ item.type }}"
placeholder="{{ item.name }}"
ng-model="item.value"
required />
</div>
<button ng-disabled="myForm.$invalid">Submit</button>
</form>
</div>
<div ng-repeat="(key1, value1) in myPersonObj">
<div ng-repeat="(key, value) in value1">
<label>{{key}}</label>
<input type="text" name="" value="{{value}}">
</div>
</div>
var app = angular.module("test",[]);
app.controller("MainCtrl",function($scope){
$scope.inputs = [
{
"firstname" : "Test"
},{
"lastname" : "Test1"
},{
"Account" : [
{"role" : "Test3"},
{"status" : "Test4"},
]
},
{
"Account1" : [
{"role" : "Test3"},
{"status" : "Test4"},
]
},
{
"Account2" : [
{"role" : {
'dim3': {
'dim4':{
'dim5':'cccc'
}
}
}
},
{"status" : "Test4"},
]
}
];
$scope.person = [];
$scope.myPersonObj = [];
/*console.log($scope.keys(inputs));*/
$scope.checkIndex1 = function(arg, myPersonObj)
{
if (angular.isArray(arg) || angular.isObject(arg)) {
angular.forEach(arg, function (value, key) {
console.log(value);
if(angular.isObject(value) || angular.isArray(value))
{
$scope.checkIndex1(value, myPersonObj);
}
else
{
console.log("pushing");
myPersonObj.push(arg);
}
});
}
else
{
console.log("pushing1");
myPersonObj.push(arg);
}
}
$scope.checkIndex1($scope.inputs, $scope.myPersonObj);
console.log("myPersonObj :"+ JSON.stringify($scope.myPersonObj));
console.log($scope.inputs);

how to populate select option in angular

I have a dynamically created data. Based on this I am creating a form. But problem is option is not added to to the select. What is wrong in this.
customerB :
{
rows:3,
columns: 2,
name: 'customerB',
fields:
[
{type: "select", name:"teacher_id", label: "Teacher" , endpoint: "/teachers", required: true, check:[ { id : "1982", name : "Mr Bob"}, { id : "18273", name : "Mrs Katrine"} ]}
],
}
HTML
<div class="rows" ng-repeat="field in customerB">
<div class="columns" ng-repeat="newvalue in field">
<div class="controls" ng-switch="newvalue.type">
<div class="form-group">
<label class="control-label">{{newvalue.label}}</label>
<select class="form-control" ng-switch-when="select" ng-model="hiii" ng-required="newvalue.required" ng-options="item.id as item.name for item in newvalue.check">
</select>
</div>
</div>
</div>
</div>
You got an object which got an array, inside the array you got another array which is not correctly manipulating.
Try understanding the following code snippet:
HTML:
<select name="repeatSelect" id="repeatSelect">
<option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
</select>
JS
availableOptions: [
{id: '1', name: 'Option A'},
{id: '2', name: 'Option B'},
{id: '3', name: 'Option C'}
]
OR follow the link: https://docs.angularjs.org/api/ng/directive/select
This assumption might be wrong but I think in here ng-repeat="field in customerB" you are accessing object property directly without the scope variable. So you need to add whatever the scope variable name in front of the property name.
<div class="rows" ng-repeat="field in obj.customerB">
Other than that code you provided work perfectly.
Demo
angular.module("app",[])
.controller("ctrl",function($scope){
$scope.obj = { customerB :
{
rows:3,
columns: 2,
name: 'customerB',
fields:
[
{type: "select", name:"teacher_id", label: "Teacher" , endpoint: "/teachers", required: true, check:[ { id : "1982", name : "Mr Bob"}, { id : "18273", name : "Mrs Katrine"} ]}
],
}}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div class="rows" ng-repeat="field in obj.customerB">
<div class="columns" ng-repeat="newvalue in field">
<div class="controls" ng-switch="newvalue.type">
<div class="form-group"> <label class="control-label">{{newvalue.label}}</label> <select class="form-control" ng-switch-when="select" ng-model="hiii" ng-required="newvalue.required" ng-options="item.id as item.name for item in newvalue.check"></select> </div>
</div>
</div>
</div>
</div>

How to implement PhoneJS SlideOut with AngularJS?

I tried the following code:
var app = angular.module('app', ['ngRoute', 'dx'])
app.controller('IndexCtrl', function($scope){
var contacts = [
{ name: "Barbara J. Coggins", phone: "512-964-2757", email: "BarbaraJCoggins#rhyta.com", category: "Family" },
{ name: "Carol M. Das", phone: "360-684-1334", email: "CarolMDas#jourrapide.com", category: "Friends" },
{ name: "Janet R. Skinner", phone: "520-573-7903", email: "JanetRSkinner#jourrapide.com", category: "Work" }
];
$scope.slideOutOptions = {
dataSource: contacts,
itemTemplate: 'item',
menuItemTemlate: 'menuItem'
}
})
<!-- HTML -->
<div class="app-index" ng-controller="IndexCtrl">
<div dx-slideout="slideOutOptions">
<div data-options="dxTemplate: { name: 'item' }">
<h1 data-bind="text: category"></h1>
<p><b>Name:</b> <span data-bind="text: name"></span></p>
<p><b>Phone:</b> <span data-bind="text: phone"></span></p>
<p><b>e-mail:</b> <span data-bind="text: email"></span></p>
</div>
<div data-options="dxTemplate: { name: 'menuItem' }">
<b data-bind="text: name"></b>
</div>
</div>
</div>
AngularJS there is not enough documentation on the DevExpress site. there are only examples using Knockout. Checkout PhoneJS DXSlideOut Documentation
The problem is in the HTML templates. You should use Angular syntax there.
<div dx-slideout="slideOutOptions">
<div data-options="dxTemplate: { name: 'item' }">
<h1>{{category}}</h1>
<p><b>Name:</b> <span>{{name}}</span></p>
<p><b>Phone:</b> <span>{{phone}}</span></p>
<p><b>e-mail:</b> <span>{{email}}</span></p>
</div>
<div data-options="dxTemplate: { name: 'menuItem' }">
<b>{{name}}</b>
</div>
</div>
Checkout docs about Angular approach.

Resources