Is this possible using only angular-formly? - javascript

So, I have this form, made using AngularJS here, which basically lets me create a purchase object to send to a server, i.e, it lets me select a store where I bought some items, set a "date of purchase" (just a text field for now), and add those items to the object I'm gonna send.
After the submit button it is shown how the model I'm going to send will look like, showing the id of the store, the "datetime", and an array of items.
My question is: Is there a way of doing this form using angular-formly only?
The question arises because I've been reading formly's docs and I haven't figured out how to make it create such a dynamic model as this form does, i.e., with a variable-length array of items of the purchase, or if it is at all possible.
Thanks in advance for any clue you can give me to answer this question :)
The code for the form is as follows:
(function(){
var app = angular.module('test', []);
})();
The html page:
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular.js"></script>
<script src="inab.js"></script>
<script src="PurchaseCtrl.js"></script>
</head>
<body ng-app="test">
<div ng-controller="PurchaseCtrl" class="col-md-4">
<h2>Purchase</h2>
<div class="panel panel-default">
<div class="panel-heading">Title</div>
<div class="panel-body">
<div class="form-group">
<label>Store</label>
<select class="form-control" ng-model="model.store">
<option ng-repeat="store in stores" value="{{store.id}}">{{store.name}}</option>
</select>
</div>
<div class="form-group">
<label>date-time</label>
<input class="form-control" type="text" ng-model="model.datetime"/>
</div>
<div ng-repeat="item in items">
<div class="form-group">
<div class="col-sm-2">
<label>{{item.label}}</label>
</div>
<div class="col-sm-8">
<input class="form-control" type="text" ng-model="item.nome" />
</div>
<div class="col-sm-2">
<button type="submit" class="btn btn-alert submit-button col-md-2" ng-click="removeItem()">remove item</button>
</div>
</div>
</div>
<button ng-click="addItem()">Add item</button>
</div>
</div>
<button type="submit" class="btn btn-primary submit-button" ng-click="onSubmit()">Submit</button>
<pre>{{model | json}}</pre>
</div>
</body>
</html>
The controller:
(function(){
angular.module('test').controller('PurchaseCtrl', ['$scope', function(scope){
scope.stores = [{id: 1, name:'Store 1'}, {id: 2, name: 'Store 2'}];
scope.items = [];
scope.datetime = '';
scope.store = '';
var i = 0;
scope.model = {
store: scope.store,
datetime: scope.datetime,
items: scope.items
};
scope.addItem = function(){
scope.items.push({label: 'algo' + (i++), nome:''});
}
scope.removeItem = function(){
scope.items.splice(scope.items.length - 1);
}
scope.onSubmit = function(){
console.log(scope.model);
}
}]);
})();

As #Satej commented, it was with repeated sections. Thanks :)

Related

How can I add array of object to html list by input form?

I want to create dynamic lists in my page. Where user can add item to list from form. Something like this:
w3school example
but I want add more inputs and send one object to angular function. Something like this:
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<link rel="stylesheet" href="http://www.w3schools.com/lib/w3.css">
<body>
<script>
var app = angular.module("myShoppingList", []);
app.controller("myCtrl", function($scope) {
$scope.products = [{food: "Milk", price: "1$"}, {food : "Bread", price: "1$"}, {food : "Cheese", price: "1$"}];
$scope.addItem = function () {
$scope.errortext = "";
if (!$scope.addMe) {return;}
if ($scope.products.indexOf($scope.addMe) == -1) {
$scope.products.push($scope.addMe);
} else {
$scope.errortext = "The item is already in your shopping list.";
}
}
$scope.removeItem = function (x) {
$scope.errortext = "";
$scope.products.splice(x, 1);
}
});
</script>
<div ng-app="myShoppingList" ng-cloak ng-controller="myCtrl" class="w3-card-2 w3-margin" style="max-width:400px;">
<header class="w3-container w3-light-grey w3-padding-16">
<h3>My Shopping List</h3>
</header>
<ul class="w3-ul">
<li ng-repeat="x in products" class="w3-padding-16">{{x.food}} : {{x.price}}<span ng-click="removeItem($index)" style="cursor:pointer;" class="w3-right w3-margin-right">×</span></li>
</ul>
<div class="w3-container w3-light-grey w3-padding-16">
<div class="w3-row w3-margin-top">
<div class="w3-col s10">
<input placeholder="Add shopping items here" ng-model="addMe.food" class="w3-input w3-border w3-padding">
<input placeholder="Add shopping items here" ng-model="addMe.price" class="w3-input w3-border w3-padding">
</div>
<div class="w3-col s2">
<button ng-click="addItem()" class="w3-btn w3-padding w3-green">Add</button>
</div>
</div>
<p class="w3-padding-left w3-text-red">{{errortext}}</p>
</div>
</div>
</body>
</html>
but if I added new item to my list and then I start change value in textbox so too change value in my list. There is something like pointer. If I send array of string then dont do it but I dont want connected to one string. Now I have connected to one string but I dont want it.
Thanks for all answers.
Create a copy using angular.copy() and then push that copied object to array.
Have a look at ngModelOptions to control how the model is updated:
https://docs.angularjs.org/api/ng/directive/ngModelOptions
try this:
<input placeholder="Add shopping items here"
ng-model="addMe.price"
ng-model-options="{ updateOn: 'blur' }"
class="w3-input w3-border w3-padding">
Just mess around with what JavaScript event will trigger the update.

How can I validate checkbox in angularjs?

Usually I use formName.inputName.$invalid to show error message input like this:
<input name="myInput" minlength="3" />
<span ng-show="myForm.myInput.$invalid">too short</span>
that won't be a problem.
But when I tried to validate checkbox,it seems difficult, there are the snippet at the end.
I want the effect that user should at least check one checkbox ,or you got the warning message.
How can I do that in a simple way at best?
// app.js
var formApp = angular.module('formApp', [])
.controller('formController', function($scope) {
// we will store our form data in this object
$scope.formData = {};
$scope.formData.favoriteColors = [{
'id':'1',
'name':'red'
},{
'id':'2',
'name':'green'
},{
'id':'3',
'name':'blue'
}];
$scope.cList = [];
$scope.checkList = function(index){
if($scope.myForm.favoriteColors.$pristine){
$scope.cList.push($scope.formData.favoriteColors[index]);
}
else{
angular.forEach($scope.formData.favoriteColors,function(value,key){
if(value.checked){
$scope.cList.push(value.id);
}
});
}
console.log('cList:%o',$scope.cList);
};
});
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<!-- CSS -->
<!-- load up bootstrap and add some spacing -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.min.js"></script>
<link href="http://cdn.bootcss.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet"/>
<style>
body { padding-top:50px; }
form { margin-bottom:50px; }
</style>
<!-- JS -->
<!-- load up angular and our custom script -->
<script src="lib/angular/angular.min.js"></script>
<script src="app.js"></script>
</head>
<!-- apply our angular app and controller -->
<body ng-app="formApp" ng-controller="formController">
<div class="col-xs-12 col-sm-10 col-sm-offset-1">
<h2>Angular Checkboxes and Radio Buttons</h2>
<form name="myForm">
<!-- NAME INPUT -->
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" name="name" ng-model="formData.name">
</div>
<!-- MULTIPLE CHECKBOXES -->
<label>Favorite Colors</label>
<div class="form-group">
<label class="checkbox-inline" ng-repeat="color in formData.favoriteColors">
<input type="checkbox" name="favoriteColors" ng-model="color.checked" ng-click="checkList($index)" required>{{color.name}}
</label>
<span class="danger" ng-show="myForm.favoriteColors.$invalid">Please check one color at least</span>
</div>
<!-- SUBMIT BUTTON (DOESNT DO ANYTHING) -->
<button type="submit" class="btn btn-danger btn-lg">Send Away!</button>
</form>
<!-- SHOW OFF OUR FORMDATA OBJECT -->
<h2>Sample Form Object</h2>
<pre>
dirty:{{ myForm.favoriteColors.$dirty }}
pristine:{{ myForm.favoriteColors.$pristine }}
valid:{{ myForm.favoriteColors.$valid }}
invalid:{{ myForm.favoriteColors.$invalid }}
error:{{ myForm.favoriteColors.$error }}
</pre>
</div>
</body>
</html>
Here is the live demo:http://jsbin.com/yigujoporu/1/
I use a count funtcion to update the number of checked checkbox.
Here is the live demo:http://jsbin.com/wowipi/4/edit?js,output
You can custom validation by another way
First, in your controller
$scope.cList = [];
$scope.checked = false;
$scope.checkList = function(index){
if($scope.myForm.favoriteColors.$pristine){
$scope.cList.push($scope.formData.favoriteColors[index]);
}
else{
if($scope.formData.favoriteColors[index].checked == true){
//checked
$scope.cList.push($scope.formData.favoriteColors[index]);
}else{
//uncheck
angular.forEach($scope.cList, function(value,key){
if($scope.formData.favoriteColors[index].id == value.id){
//remove it
$scope.cList.splice(key,1);
}
}
}
console.log('cList:%o',$scope.cList);
//new change
if($scope.cList.length >0) {
$scope.checked = true;
}else{
$scope.checked = false;
}
};
In your view
<div class="form-group">
<label class="checkbox-inline" ng-repeat="color in formData.favoriteColors">
<input type="checkbox" name="favoriteColors" ng-model="formData.favoriteColors[$index].checked" ng-click="checkList($index)" required>{{color.name}}
</label>
<span class="danger" ng-show="!checked">Please check one color at least</span>
</div>

ng-disabled in Angular validation not working as expected

http://plnkr.co/edit/9Yq6aZHtKCuZMtPbjBIN?p=preview
I've tried and tried to get this to work but I've had no luck. I'm trying to disable the submit button using angularJS and the built in validation function. What I find is that when you first load the form, the submit button is active--not disabled!
I've tested and tried and I've found that my validation code accepts an empty string / null string in the Team Name, despite me requiring the input.
Does anyone know how to format this correctly? The ONLY way I've gotten it to work is to fudge the data with replacing an empty string with a single space...in production this is unacceptable...
Here is the index.html:
<body ng-controller="EnterController as enter">
<div class="panel panel-primary">
<div class="panel-body">
<form name="enterFormNew" ng-submit="enter.TeamNameNext()" autocomplete="off" novalidate>
<div class="row">
<div class="col-xs-8 col-md-6">
<div class="form-group">
<label for="teamname">Team Name</label>
<input name="TeamName" ng-required ng-minlength="2" ng-maxlength="40" ng-model="enter.Team.Name" type="text" id="teamname" class="form-control" />
<p ng-show="enterFormNew.TeamName.$touched && enterFormNew.TeamName.$invalid">This is not a valid team name.</p>
</div>
<div class="form-group">
<label for="division">Division</label>
<select name="selectDivision" ng-required ng-model="enter.Team.Division" id="division" class="form-control" ng-options="division.Name for division in enter.Divisions track by division.Id ">
<option value="">Select...</option>
</select>
<p ng-show="enterFormNew.selectDivision.$touched && enterFormNew.selectDivision.$invalid">A valid Division needs to be selected.</p>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-2">
<button type="submit" class="btn btn-primary" ng-disabled="enterFormNew.$invalid">Next</button>
</div>
</div>
</form>
</div>
</div>
</body>
And here is the app.js:
angular.module('Enter', [])
.controller("EnterController", [
function() {
this.RegistrationPhase = 0;
this.Divisions = [{ Id: 1,Name: "Normal"}, {Id: 2,Name: "Not Normal"}];
this.Team = { Name: "", ResumeKey: null, Division: { Id: -1 }, Players: []};
this.TeamNameNext = function() {
//Code removed
alert("Made it to the submit function!")
};
}
]);
the attribute ng-required requires a value. Don't get confused with HTML5 attribute required that doesn't require a value.
ng-required="true"
Because "Team.Division" is not undefined in your controller code.
If you could use the code below, you will get what you extected.
this.Team = { Name: "", ResumeKey: null, Division: undefined, Players: []};
You can use null or "" instead of undefined.

Javascript Remove a Template Element

I have a template that I will simplify as follows:
<script type="text/template" id="contactTemplate">
<div id="contactentry" class="row contact-info">
</div>
<div class="form-group">
<label for="name1">First Name</label>
<input type="text" class="form-control" id="FirstName" name="Contacts[{{ID}}].FirstName" required>
</div>
<div class="form-group minus">
<label for="contactMinus{{ID}}"> </label>
<a id="depminus{{ID}}"><i class="fa fa-minus-circle"></i>Remove</a>
</div>
</script>
I allow insertion of the template, multiple times via the following code, this part works:
<script type="text/javascript">
var clone = (function () {
var cloneIndex = -1;
var template = $('#contactTemplate').text();
return function () {
//Replace all instances of {{ID}} in our template with the cloneIndex.
return template.replace(/{{ID}}/g, ++cloneIndex);
}
})();//self executing function.
var contacts = $('#contacts')
$("#contactadd").on("click", function () {
contacts.append(clone());
window.controlManager.FindControls(contacts);
});
</script>
<div id='contacts'>
<div class="col col-lg-1">
<a id="contactadd"><i class="fa fa-plus-circle"></i>Add</a>
</div>
</div>
Now I am trying to figure out how to make javascript code to remove each element when/if the minus button is clicked (in the template).
I'm not sure what kindof code I could then use to delete the contacts, via the depminus{{ID}} control. Any tips to get me started?

How to add HTML contents Dynamically on Button Click Event with AngularJS

I need to add HTML content on Button Click event using AngularJS. Is it possible??
My index.html
<div class="form-group">
<label for="category"> How Many Questions Want You Add ? </label>
<div class="col-sm-10">
<input type="text" class="form-control input-mini" id="questionNos" name="questionNos" placeholder="Nos." ng-model="myData.questionNos">
<div class="input-append">
<button class="btn-warning btn-mini" type="button" ng-click="myData.doClick()">Generate</button>
</div>
</div>
</div>
I want to add Nos. of HTML divs as per quantity added dynamically..
myApp.js
angular.module("myApp", []).controller("AddQuestionsController",
function($scope) {
$scope.myData = {};
$scope.myData.questionNos = "";
$scope.myData.doClick = function() {
//Do Something...????
};
});
It should be possible. I would data-bind your Divs to viewModel elements, and in your doClick function create the viewModels.
I would avoid directly creating Html in your viewModel.
For example:
<div class="form-group">
<label for="category"> How Many Questions Want You Add ? </label>
<div class="col-sm-10">
<input type="text" class="form-control input-mini" id="questionNos" name="questionNos" placeholder="Nos." ng-model="myData.questionNos">
<div class="input-append">
<button class="btn-warning btn-mini" type="button" ng-click="myData.doClick()">Generate</button>
</div>
<div ng-repeat="q in myData.questions">
<!-- BIND TO Q HERE -->
</div>
</div>
</div>
And in doClick:
$scope.myData.doClick = function() {
var newQuestions = getNewQuestionViewModels($scope.myData.questionNos);
for (var i = 0; i < newQuestions.length; i++) {
$scope.myData.questions.push(newQuestions[i]);
}
};
You have to store questions in collection and do repeat.
DEMO
HTML:
<div>
<input type="text" ng-model="data.qcount">
<button type="button" ng-click="data.add()">Add</button>
</div>
<div>
<div ng-repeat="q in data.questions track by $index">
<pre>{{ q | json }}</pre>
</div>
</div>
JS:
$scope.data = {
questions: [],
qcount: 0,
add: function() {
var dummy = {
'title': 'Q title',
'body': 'Q body'
},
newQ = [];
for (var i = 0; i < $scope.data.qcount; ++i) {
newQ.push(dummy);
}
$scope.data.questions = $scope.data.questions.concat(newQ);
$scope.data.qcount = 0;
}
};

Categories