AngularJS dynamic Form does not get valid - angularjs

I have a dynamic Form in AngularJS, the input tags get replaced according to question type selected by the user. So the problem is, when user left a input tag blank which is required and switched to another type of questions, the form remains invalid(even the current form is valid).
I am adding the JsFiddle for it, you will get the idea.
HTML
<body ng-app="myApp" ng-controller="myCtrl">
<form name="myForm" novalidate>
<div><input name='name' type='text' ng-model='name' ng-required='true' placeholder='name'></div>
<div compile="myHtml"></div>
<input type="radio" ng-required='true' ng-click="addQuestion(1)" ng-model="radio" value="1"> Question 1 & 3
<input type="radio" ng-required='true' ng-click="addQuestion(2)" ng-model="radio" value="2"> Question 2 & 4
<input type="submit" name="submit" ng-click="" ng-disabled="myForm.$invalid">
</form>
</body>
Javascript
// the main (app) module
var myApp = angular.module("myApp", []);
// add a controller
myApp.controller("myCtrl", function($scope) {
$scope.name = "John Doe";
$scope.myHtml = "";
$scope.radio="1";
$scope.question1 = 1;
$scope.question2 = 2;
$scope.question4 = 4;
$scope.addQuestion = function(id) {
$scope.myHtml = "";
if(id == 1) {
$scope.myHtml += "<div><input name='question1' type='text' ng-model='question1' ng-required='true' placeholder='Question 1'></div>";
$scope.myHtml += "<div><input name='question3' type='text' ng-model='question3' ng-required='true' placeholder='Question 3'></div>";
};
if(id == 2) {
$scope.myHtml += "<div><input name='question2' type='text' ng-model='question2' ng-required='true' placeholder='Question 2'></div>";
$scope.myHtml += "<div><input name='question4' type='text' ng-model='question4' ng-required='true' placeholder='Question 4'></div>";
};
};
$scope.addQuestion(1);
});
// add a directive
myApp.directive('compile', ['$compile', function ($compile) {
return function(scope, element, attrs) {
scope.$watch(
function(scope) {
// watch the 'compile' expression for changes
return scope.$eval(attrs.compile);
},
function(value) {
// when the 'compile' expression changes
// assign it into the current DOM
element.html(value);
// compile the new DOM and link it to the current
// scope.
// NOTE: we only compile .childNodes so that
// we don't get into infinite loop compiling ourselves
$compile(element.contents())(scope);
}
);
};
}]);
Server JSON for question
$scope.fields = [{
"caption": "Gender",
"questionType": "RADIO",
"optionValues": ["Male", "Female"],
"fieldPriority": "REQUIRED"
}, {
"caption": "City",
"questionType": "TEXT",
"optionValues": "",
"fieldPriority": "REQUIRED"
}, {
"caption": "Address",
"questionType": "PARAGRAPH_TEXT",
"optionValues": "",
"fieldPriority": "REQUIRED"
}, {
"caption": "Nationality",
"questionType": "LIST",
"optionValues": ["Indian", "American"],
"fieldPriority": "REQUIRED"
}, {
"caption": "Tea/Coffee",
"questionType": "CHECKBOX",
"optionValues": ["Tea", "Coffee"],
"fieldPriority": "REQUIRED"
}];
Thanks

Do not store plane html in controller. Just use ng-if or ng-show to handle your logic.

I'd refactor your code to use ng-include instead of compiling html from controller which is completely bad pattern in angularjs.
You could inject the template on basis of radio value ng-model
<body ng-app="myApp" ng-controller="myCtrl">
<form name="myForm" novalidate>
<div>
<input name='name' type='text' ng-model='name' ng-required='true' placeholder='name'/>
</div>
<div ng-include="'question-set-'+radio +'.html'"></div>
<input type="radio" ng-required='true' ng-click="addQuestion(1)" ng-model="radio" value="1" />Question 1 & 3
<input type="radio" ng-required='true' ng-click="addQuestion(2)" ng-model="radio" value="2" />Question 2 & 4
<input type="submit" name="submit" ng-click="" ng-disabled="myForm.$invalid">
</form>
</body>
<script type="text/ng-template" id="question-set-1.html">
<div> <input name = 'question1' type='text' ng-model = 'question1' ng-required = 'true' placeholder = 'Question 1' /> </div>
<div><input name='question3' type='text' ng-model='question3' ng-required='true' placeholder='Question 3'/> </div>
</script>
<script type="text/ng-template" id="question-set-2.html">
<div><input name ='question2' type ='text' ng-model='question2' ng-required = 'true' placeholder = 'Question 2' /> </div>
<div><input name='question4' type='text' ng-model='question4' ng-required='true' placeholder='Question 4'/> </div>
</script>
Working Fiddle

Related

angularjs checkbox Incorrect response in console

I have two criteria:
1) Only allow one of two boxes selected at one time.
2) Capture the name of the box that is selected.
However, when I print out the list of checkbox objects they are correct, but when I check in the console they are not correct. For example,
HTML:
<div ng-repeat="treatment in treatment_list">
<input type="checkbox" value="{{treatment.name}}"
ng-model="treatment.checked"
ng-click="updateTreatment($index, treatment_list);
checkedTreatment(treatment_list)">
<label>Treatment {{treatment.name.toUpperCase()}}</label></input><br>
</div>
{{treatment_list}}
Controller:
$scope.treatment_list = [
{
name: 'a',
checked: false
}, {
name: 'b',
checked: false
}
];
$scope.updateTreatment = function(position, treatment_list) {
console.log(treatment_list);
angular.forEach(treatment_list, function(treatment, index) {
console.log(treatment.name, treatment.checked);
if (position != index) {
treatment.checked = false;
}
});
};
$scope.$watch('treatment.checked', function (treatment) {
console.log(treatment);
});
Plunker:
https://plnkr.co/edit/Hkb4IeKxi0TRqHRJA4JN?p=preview
Inorder to fullfill your requirement you should just use a radio box whith ng-model, it will work out of the box for you.
Use radio buttons instead:
angular.module("app",[])
.controller('ExampleController', function($scope) {
$scope.color = {
name: 'blue'
};
$scope.specialValue = {
"id": "12345",
"value": "green"
};
$scope.colorChange = function(color) {
console.log(color);
};
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<form name="myForm" ng-controller="ExampleController">
<label>
<input type="radio" ng-model="color.name" value="red"
ng-change="colorChange(color.name)" />
Red
</label><br/>
<label>
<input type="radio" ng-model="color.name" ng-value="specialValue"
ng-change="colorChange(color.name)" />
Green
</label><br/>
<label>
<input type="radio" ng-model="color.name" value="blue"
ng-change="colorChange(color.name)" />
Blue
</label><br/>
<tt>color = {{color.name | json}}</tt><br/>
</form>
Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
</body>
For more infomation, see AngularJS input type=radio Directive API Reference

How to create a "other" or "catch all" radio button?

Suppose I want to present a few default options for the user but also want to allow them to enter their own value.
e.g.
Please select one of the following:
[ ] apple
[ ] pear
[ ] other: ___________
I want it so that if "other" is selected, then the input field that follows should be enabled and allow typing.
Html might look like this:
<input type="radio"
name="fruit"
ng-model="fruit"
value="apple"
> apple
<input type="radio"
name="fruit"
ng-model="fruit"
value="pear"
> pear
<input type="radio"
name="fruit"
ng-model="???"
value="???"
> Other:
<input type="text"
class="form-control"
ng-model="fruit"
ng-disabled="???">
What would you do here?
I had an implementation where the default options trigger an action on ng-change such that it changed a $scope.isOther to true, which would enable the input box and check the other radio box like so
<input type="radio"
name="fruit"
ng-model="fruit"
value="apple"
ng-change="isOther=true"
> apple
<input type="radio"
name="fruit"
ng-model="fruit"
value="pear"
ng-change="isOther=true"
> pear
<input type="radio"
name="fruit"
ng-model="isOther"
ng-change="fruit=null"
value="true"
> Other:
<input type="text"
class="form-control"
ng-model="fruit"
ng-disabled="!isOther">
That sort of works. But when I reload the page/data, if I have an "other" value entered, it doesn't know to automatically check "other", although my "other" value is in the input box. I could write some more code change the isOther value when I'm loading the data but I'm wondering if I'm even going about this the right way or whether there's a "catch all" that allows a radio box to be checked if it doesn't match any other values.
You can do it this way:
var myapp = angular.module('myApp', []);
myapp.controller('MyController', function($scope) {
$scope.fruits = ['apple', 'orange', 'plum', 'pear'];
$scope.fruit = {selectedOption: 'orange'};
$scope.isDisabled = function() {
if (_.contains($scope.fruits, $scope.fruit.selectedOption)) {
return true;
}
return false;
};
$scope.add = function() {
if($scope.x !== undefined && $scope.x !== '') {
$scope.fruits.push($scope.x);
$scope.fruit.selectedOption = $scope.x;
$scope.x = '';
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div id='main' ng-app='myApp'>
<form name="myForm" ng-controller="MyController">
<div ng-repeat="f in fruits track by $index">
<input type="radio" name="fruit" ng-model="fruit.selectedOption" value={{f}}> {{f}}
</div>
<input type="radio" name="fruit" ng-model="fruit.selectedOption" value="other"> Other:
<input type="text" ng-model="x" ng-disabled="isDisabled()" ng-blur="add()">
<br> fruit = {{fruit.selectedOption}}
</form>
</div>
JSFiddle
I don't have a perfect answer, but I ended up doing it this way
html:
<div id='main' ng-app='myApp'>
<form name="myForm" ng-controller="MyController">
<div ng-repeat="f in fruits track by $index">
<input type="radio" name="fruit" ng-model="fruit.value" ng-value="f" ng-change="disableOther()"> {{f}}
</div>
<input type="radio" name="otherfruit" ng-change="fruit.value=null" ng-model="isOther" ng-value="true"> Other:
<input type="text" ng-model="fruit.value" ng-change="checkOther()" ng-class="{'disabled-input':isStandardFruit()}">
<br> fruit = {{fruit.value}}
</form>
</div>
code:
var myapp = angular.module('myApp', []);
myapp.controller('MyController', function($scope) {
$scope.fruits = ['apple', 'orange', 'plum', 'pear'];
$scope.fruit = {value:'orange'};
$scope.isStandardFruit = function() {
for(var i=0; i<$scope.fruits.length; i++) {
if( $scope.fruits[i] == $scope.fruit.value ) {
return true;
}
}
return false;
}
$scope.disableOther = function() {
$scope.isOther = false;
}
$scope.checkOther = function() {
if( !$scope.isStandardFruit() ) {
$scope.isOther = true;
}
}
});
JSFiddle
The one drawback is that if you type a standard fruit into the "other" input box, then it selects multiple radio buttons. I could uncheck the "other" button but then you couldn't type a fruit that contained the standard fruit as a prefix (e.g. you wouldn't be able to type "apple pear")
If anyone can come up with a better answer, I will change my vote and answers

Reloading form does not update in AngularJS?

I am creating a form, where when the user clicks on the edit button to edit the text, it works fine. But when user clicks on the update button then reload the page it does not show the updated text after reloading the page.
Here is the plunker, that it worked but the code below does not work when page reloads. (I want to do this only with Front-End)
http://plnkr.co/edit/yyDf2SuEvefLWIK13kS4?p=preview
Here is my code.
<div class="people-view">
<h2 class="name">{{people.first}}</h2>
<h2 class="name">{{people.last}}</h2>
<span class="title">{{people.title}}</span>
<span class="date">{{people.date}} </span>
</div>
<div ng-controller="MyCtrl">
<div class="list-view">
<form>
<fieldset ng-disabled="inactive">
<legend>Basic Info</legend>
<b>First Name:</b>
<input type="text" ng-model="people.first">
<br>
<b>Last Name:</b>
<input type="text" ng-model="people.last">
<br>
<b>Email:</b>
<input type="email" ng-model="people.email">
<br>
<b>Phone:</b>
<input type="num" ng-model="people.phone">
<br>
<b>Website:</b>
<input type="text" ng-model="people.website">
<br>
<b>Education:</b>
<input type="text" ng-model="people.education">
<br>
<b>Education Year:</b>
<input type="text" ng-model="people.year">
<br>
<legend>Address</legend>
<b>Street:</b>
<input type="text" ng-model="people.street">
<br>
<b>City:</b>
<input type="text" ng-model="people.city">
<br>
<b>State:</b>
<input type="text" ng-model="people.state">
<br>
<b>Zip:</b>
<input type="text" ng-model="people.zip">
<br>
</fieldset>
<button type="button" class="edit" ng-show="inactive" ng-click="inactive = !inactive">
Edit
</button>
<button type="submit" class="submit" ng-show="!inactive" ng-click="save()">Save</button>
</form>
</div>
</div>
App.js
var app = angular.module("Portal", []);
app.controller('MyCtrl', function($scope) {
$scope.inactive = true;
$scope.save = function() {
$scope.msg = 'Data sent: '+ JSON.stringify($scope.people);
};
});
JSON file
[
{
"id": "0",
"first": "John",
"last": "Smith",
"img": "//placehold.it/100x100",
"title": "Family",
"date": "Joined 4/2/17",
"email": "jsmith#email.com",
"phone": "555-555-5555",
"website": "www.google.com",
"education": "NYU Law",
"year": "2008",
"street": "123 Main Street",
"city": "Los Angeles",
"state": "CA",
"zip": "1234567"
},
]
Controller
app.controller('PeopleController',['$scope', 'people', '$routeParams',
function($scope, people, $routeParams) {
people.success(function(data) {
$scope.people = data[$routeParams.id];
});
}]);
You can try using the prevent default handler:
ng-click="save($event)"
In your controller, you can put:
$scope.save = function (event) {
event.preventDefault();
$scope.msg = 'Data sent: '+ JSON.stringify($scope.people);
}
to make your changes permanent you have to store it to some sort of storage. files is ok but it's not the best choice. So you may consider using local storage. here is good tutorial of how to handle
local-storage. so the controller will be like
app.controller('myCtrl', ['$scope', function($scope){
$scope.people = {
"first": "John",
"last": "Smith"
}
$scope.myObject = JSON.parse(localStorage.getItem('myObject')) || {
first : $scope.people.first,
last : $scope.people.last
};
$scope.updateThingy = function(){
$scope.people.first = $scope.myObject.first;
$scope.people.last = $scope.myObject.last;
localStorage.setItem('myObject', JSON.stringify($scope.myObject));
};
}]);
here is the plunker. Good luck

adding input values from form to json object using angularjs

am trying to add the value of input field to json object using angularjs i wrote some codes but it doesn't work, please i need help
script section
<script>
var app = angular.module("exampleApp", []);
app.controller("defaultCtrl", function ($scope, $http) {
$scope.loadData = function () {
$http.get("productData.json").then(function (response) {
console.log("Status: " + response.status);
console.log("Type: " + response.headers("content-type"));
console.log("Length: " + response.headers("content-length"));
$scope.products = response.data;
});
$scope.products = {name:'',age:'',isDead:''};
$scope.resurrect = function(item){
item.isDead = false;
};
$scope.addnew = function(){
$scope.products.mname = $scope.products.name;
$scope.products.mage = $scope.products.age;
$scope.products.misDead = $scope.products.isDead;
};
}
});
</script>
productData.json
[
{ "name": "Tommen Baratheon", "age": "23", "isDead": true },
{ "name": "Roose Bolton", "age": "32", "isDead": false },
{ "name": "Theon Greyjoy", "age": "27", "isDead": true},
{ "name": "Cersei Lannister", "age": "31", "isDead": false}
]
form section
<form>
<input type="text" placeholder="Enter Charater name" class="form- control" ng-model="products.mname">
<input type="number" placeholder="Enter Charater age" class="form-control" ng-model="products.mage">
<input type="text" placeholder="Enter True or false" class="form-control" ng-model="products.misDead">
<input type="submit" value="andNew" ng-submit="addnew()"></form>
So the first problem is that $scope.products is an array. Your markup is bound as if it's a single object though.
<form>
<div ng-repeat="p in products">
<input type="text" placeholder="Enter Charater name" class="form-control" ng-model="p.name">
<input type="number" placeholder="Enter Charater age" class="form-control" ng-model="p.age">
<input type="text" placeholder="Enter True or false" class="form-control" ng-model="p.isDead">
<input type="submit" value="andNew" ng-submit="addnew()">
</div>
</form>
The other problem was that you had bindings like products.mname, but the field is actually name. The next problem you have is you're initializing products as an object when you really should just initialize it as an empty array:
$scope.products = [];
The next problem you'll have is addnew. It needs to just push a new object on to the array:
$scope.addnew = function() {
$scope.products.push({});
};
That will cause a new div to be rendered inside the form.

AngularJS - Trigger when radio button is selected

I searched and tried many ng-xxxx kind of options but couldn't find the one..
I just want to call some function in the controller when radio button is selected.
So it might be similar to following..(Of course, below code is not working)
<input type="radio" ng-model="value" value="one" ng-click="checkStuff()"/>
Is there any way to achieve what I want?
There are at least 2 different methods of invoking functions on radio button selection:
1) Using ng-change directive:
<input type="radio" ng-model="value" value="foo" ng-change='newValue(value)'>
and then, in a controller:
$scope.newValue = function(value) {
console.log(value);
}
Here is the jsFiddle: http://jsfiddle.net/ZPcSe/5/
2) Watching the model for changes. This doesn't require anything special on the input level:
<input type="radio" ng-model="value" value="foo">
but in a controller one would have:
$scope.$watch('value', function(value) {
console.log(value);
});
And the jsFiddle: http://jsfiddle.net/vDTRp/2/
Knowing more about your the use case would help to propose an adequate solution.
Should use ngChange instead of ngClick if trigger source is not from click.
Is the below what you want ? what exactly doesn't work in your case ?
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.value = "none" ;
$scope.isChecked = false;
$scope.checkStuff = function () {
$scope.isChecked = !$scope.isChecked;
}
}
<div ng-controller="MyCtrl">
<input type="radio" ng-model="value" value="one" ng-change="checkStuff()" />
<span> {{value}} isCheck:{{isChecked}} </span>
</div>
In newer versions of angular (I'm using 1.3) you can basically set the model and the value and the double binding do all the work this example works like a charm:
angular.module('radioExample', []).controller('ExampleController', ['$scope', function($scope) {
$scope.color = {
name: 'blue'
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<html>
<body ng-app="radioExample">
<form name="myForm" ng-controller="ExampleController">
<input type="radio" ng-model="color.name" value="red"> Red <br/>
<input type="radio" ng-model="color.name" value="green"> Green <br/>
<input type="radio" ng-model="color.name" value="blue"> Blue <br/>
<tt>color = {{color.name}}</tt><br/>
</form>
</body>
</html>
For dynamic values!
<div class="col-md-4" ng-repeat="(k, v) in tiposAcesso">
<label class="control-label">
<input type="radio" name="tipoAcesso" ng-model="userLogin.tipoAcesso" value="{{k}}" ng-change="changeTipoAcesso(k)" />
<span ng-bind="v"></span>
</label>
</div>
in controller
$scope.changeTipoAcesso = function(value) {
console.log(value);
};
Another approach is using Object.defineProperty to set valueas a getter setter property in the controller scope, then each change on the value property will trigger a function specified in the setter:
The HTML file:
<input type="radio" ng-model="value" value="one"/>
<input type="radio" ng-model="value" value="two"/>
<input type="radio" ng-model="value" value="three"/>
The javascript file:
var _value = null;
Object.defineProperty($scope, 'value', {
get: function () {
return _value;
},
set: function (value) {
_value = value;
someFunction();
}
});
see this plunker for the implementation
i prefer to use ng-value with ng-if,
[ng-value] will handle trigger changes
<input type="radio" name="isStudent" ng-model="isStudent" ng-value="true" />
//to show and hide input by removing it from the DOM, that's make me secure from malicious data
<input type="text" ng-if="isStudent" name="textForStudent" ng-model="job">
<form name="myForm" ng-submit="submitForm()">
<label data-ng-repeat="i in [1,2,3]"><input type="radio" name="test" ng-model="$parent.radioValue" value="{{i}}"/>{{i}}</label>
<div>currently selected: {{radioValue}}</div>
<button type="submit">Submit</button>
</form>

Resources