Angularjs: Dynamic Input in a single array for row - javascript

I'm a newbie and I need some help for something you'll maybe find too easy.
I want to add with a single button different inputs at the same time.
I don't know how to manage.
This is what I'm doing, and I'm blocked.
I'll thank you your ideas.
So, my form shows each name and an input box for entering the age of that person (We don't know how many persons are in 'people').
And in the end, an 'submit' button that calls the showAll() function.
And then, I just want to show the content of the array in console.log
A Form like this:
Form with only 3 people
HTML:
<form name="myForm3">
<div class="form-group row" ng-repeat="person in people track by $index">
<label for="player" class="col-xs-3 col-form-label text-right">{{ person.name }}</label>
<div class="col-xs-2">
<input class="form-control" type="text" ng-model="person.age[$index]" required>
</div>
</div>
<button type="submit" class="btn btn-success btn-lg" ng-click="showAll()" >Show all</button>
</form>
controller.js:
$scope.person = [];
// POST
$scope.showAll = function() {
for (var i=0; i < person.length; i++){
console.log('person: ' + {{ $scope.person[i] }} );
}
}

you can hide the inputs by using ng-if or ng-hide and show them on showAll by setting that variable used by those to true or false:
<div class="col-xs-2" ng-if="person.show">
<input class="form-control" type="text" ng-model="person.age[$index]" required>
</div>
And in showAll:
$scope.showAll = function() {
for (var i=0; i < $scope.people.length; i++) {
$scope.people[i].show = true;
}
};

Related

What is the easiest way to make editForm in Angular?

In my database i have many users which has many recipes.
Every recipe has some properties and collection of ingredients.
Below is screenshot
Recipe with all properties
So when user display recipe to edit on page should appear (form) recipe with loaded current data. This is kind of working because i can see the data but i think it's no done good.
I have form which is working fine without array (ingredients). Could you tell me how i should add ingredients to my edit form?
I'd be grateful if you see at my code and give me feedback and hints what i should change.
export class RecipeEditComponent implements OnInit {
#ViewChild('editForm') editForm: NgForm;
recipe: IRecipe;
photos: IPhoto[] = [];
ingredients: IIngredient[] = [];
uploader: FileUploader;
hasBaseDropZoneOver = false;
baseUrl = environment.apiUrl;
currentMain: IPhoto;
constructor(private route: ActivatedRoute, private recipeService: RecipeService,
private toastr: ToastrService) { }
ngOnInit(): void {
this.loadRecipe();
}
loadRecipe() {
this.recipeService.getRecipe(this.route.snapshot.params.id).subscribe(recipe => {
this.recipe = recipe;
this.initializeUploader();
})
}
updateRecipe(id: number) {
this.recipeService.editRecipe(id, this.recipe).subscribe(next => {
this.toastr.success('Recipe updated successfully');
this.editForm.reset(this.recipe);
}, error => {
this.toastr.error(error);
});
}
}
HTML
<div class="container mt-4 border" *ngIf="recipe">
<form #editForm="ngForm" id="editForm" (ngSubmit)="updateRecipe(recipe.id)" >
<h5 class=" text-center mt-2">Recipe details:</h5>
<div class="form-group mt-3">
<label for="city">Name</label>
<input class="form-control" type="text" name="name" [(ngModel)]="recipe.name">
</div>
<div class="form-group">
<app-ingredient-editor [ingredients] = "recipe.ingredients"></app-ingredient-editor>
<div *ngFor="let ingredient of recipe.ingredients; let i = index">
<input class="form-control" type="text" name="{{ingredient.name}}" [(ngModel)]="ingredient.name">
<input class="form-control" type="text" name="{{ingredient.amount}}" [(ngModel)]="ingredient.amount">
</div>
</div>
<div class="form-group">
<br>
<p>Add recipes</p>
</div>
<h5 class=" text-center mt-4">Description</h5>
<angular-editor cols=100% rows="6" [placeholder]="'Your description'" [(ngModel)]="recipe.description" name="description"></angular-editor>
</form>
<button [disabled]="!editForm.dirty" form="editForm" class="btn btn-success btn-block mb-5 mt-5">Save changes</button>
</div>
For now it's look like:
Form on page
When i delete ingredient name while changing on the console i have following error:
recipe-edit.component.html:12 ERROR Error: If ngModel is used within a form tag, either the name attribute must be set or the form
control must be defined as 'standalone' in ngModelOptions.
Problem is that part of code:
<div *ngFor="let ingredient of recipe.ingredients; let i = index">
<input class="form-control" type="text" name="{{ingredient.name}}" [(ngModel)]="ingredient.name">
<input class="form-control" type="text" name="{{ingredient.amount}}" [(ngModel)]="ingredient.amount">
</div>
</div>
But i don't know how to make it working..
How to add add array to template-driven form?
In my case i need to display current ingredients and be able to edit them.
I have tried something like this :
<input class="form-control" type="text" name="ingredient[i].name" [(ngModel)]="ingredient[i].name">
<input class="form-control" type="text" name="ingredient[i].amount" [(ngModel)]="ingredient[i].amount">
But id doesn't work
The problem is that the property name on the form must be defined in order for angular to know which input to update. You're binding name to the same property that the editable model is set to which means the user can edit it and in fact delete it, which isn't good.
The solution is to change it to a unique value that doesn't change. This should work:
<div *ngFor="let ingredient of recipe.ingredients; let i = index">
<input class="form-control" type="text" name="name{{ingredient.id}}" [(ngModel)]="ingredient.name">
<input class="form-control" type="text" name="amount{{ingredient.id}}" [(ngModel)]="ingredient.amount">
</div>
</div>
Link to stackblitz showing it working: https://stackblitz.com/edit/angular-10-base-template-q243lw?file=src%2Fapp%2Fapp.component.html
Edit: fixed bug in original post and added link to stackblitz

Get element by name using knockout

I am creating input elements like below:
<input type="text" class="form-control" data-bind="value: attr: { name: Data[' + $index() + ']'}" />
I have another button which creates multiple inputs of above with its click.
And I also have my main button click as:
<input type="button" value="Check Data" class="btn btn-primary" data-bind='click: verify.bind($data, event)' />
In my knockout I have:
self.verify= function (data, event) {
//here I want the data that is entered in each of the inputs.
}
On the above button click I want to get the value of all the inputs. In JS I could have done elements by name and it would give me that element. But how can I get that to work here.
Updated code:
I have this in my HTML:
<div data-bind="foreach: { data: myData }">
<div class="form">
<div class="myClass">
<input type="text" class="form-control" data-bind="value: $data.textbox, attr: { name: 'MyData[' + $index() + '].Textbox'}" />
</div>
<div class="myClass">
<input type="button" value="Add More" class="btn btn-primary" data-bind="click: $parent.add"/>
</div>
</div>
</div>
When the user clicks Add More, it adds on more it adds one more text box.
Then at last I have a button as:
<div class="form">
<input type="button" value="Check Data" class="btn btn-primary" data-bind='click: checkData' />
</div>
When the user clicks on Check Data button I just need to some validation on the all the data entered in the textbox. The validation needs to be done on client side.
In my knockout I have:
this.add = ko.observableArray();
this.add = function () {
self.myData.push(
{
textbox: ""
});
};
this.checkData = function (){
//Here I want to get whats entered in all the textboxes
}
It's exceedingly likely that your entire approach is wrong.
Your HTML input elements don't need names.
Your viewmodel methods do not need to know anything about the HTML elements that display their values.
You do not need to bind your event handlers with special parameters.
The view (the HTML page) is used as a tool for modifying the viewmodel. All data you need for verification is in the viewmodel, given that you have made everything that the user can change an observable.
function Test() {
var self = this;
self.users = ko.observableArray([
{ name: ko.observable("John Doe") },
{ name: ko.observable("Jane Doe") }
]);
self.verify = function () {
var usernames = self.users().map(function (u) { return ko.unwrap(u.name) });
alert('You have entered these users\n\n' + usernames.join('\n'));
};
}
var vm = new Test();
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="foreach: users">
<input type="text" class="form-control" data-bind="value: name" /><br>
</div>
<button class="btn btn-primary" data-bind='click: verify'>Check Data</button>

dynamic form field with checkbox in angularjs

I want to submit values of the input field to controller with ng-submit but it shows undefined when i console input model.Each input values are saved with check box. But i want to check if any checkbox is unchecked or not.
Here is form html:
<form id="valueForm" ng-submit="submitValues()">
<div class="small-input list padding" style="padding-top:4px;">
<div ng-repeat="item in inputs track by $index">
<label class="item item-input">
<input type="text" placeholder="" ng-model="value" ng-disabled="ticked">
<ion-checkbox ng-click="addField($index)" ng-change="saveValue(ticked,value,$index)" ng-model="ticked"
ng-disabled="!value" style="border: none;padding-left: 30px;" class="checkbox-royal"></ion-checkbox>
</label>
</div>
</div>
<button type="submit" ng-show="showButton" class="button button-dark button-shadow pull-right" style="" ><i class="ion-ios-arrow-forward"></i></button>
</form>
Here is controller:
$scope.showButton = false;
$scope.inputs = [{value:''}];
var checkedValues =[];
$scope.addField = function (index) {
if($scope.inputs.length <= index+1 && $scope.inputs.length<10){
$scope.inputs.splice(index+1,0,name);
}
}
$scope.saveValue = function (ticked,item,index) {
if(ticked){
console.log('index'+index);
if(index>0) $scope.showButton =true;
checkedValues.splice(index,0,item);
console.log(checkedValues);
}else{
checkedValues.splice(index,1);
console.log(checkedValues);
}
}
$scope.submitValues = function(){
console.log($scope.value);
}
Because the inputs and checkboxes are inside an ng-repeat directive, the ng-model values need to be a property of the item iterator.
<form id="valueForm" ng-submit="submitValues()">
<div ng-repeat="item in inputs track by $index">
<!-- REMOVE
<input type="text" ng-model="value" ng-disabled="ticked">
<ion-checkbox ng-model="ticked"> </ion-checkbox>
-->
<!-- INSTEAD -->
<input type="text" ng-model="item.value"
ng-disabled="item.ticked">
<ion-checkbox ng-model="item.ticked"> </ion-checkbox>
</div>
<button type="submit" ng-show="showButton">
<i class="ion-ios-arrow-forward"></i>
</button>
</form>
The ng-repeat directive creates a child scope for each item. Using a value without a "dot" will put the value on each child scope. Hence the rule: "always use a 'dot' in your ng-models".
For more information, see AngularJS Wiki -- The Nuances of Prototypical Inheritance
UPDATE
To see the inputs on submit:
$scope.submitValues = function(){
//console.log($scope.value);
console.log($scope.inputs);
}

Angular hide inputs in ng-repeat table rows

How would i hide input elements and replace there value to the table rows , the inputs are dynamically created with push see below code :
view
ID LIKE TO REPLACE THE INPUTS WITH THE VALUE OF INPUTS IN THE TABLE ROWS
<tr class="odd gradeX" ng-repeat="choice in vm.choices">
<td>Add</td>
<td>save</td>
<td>
<div class="form-group">
<div class="input-group">
<input type="text" placeholder="Item Name" class="form-control" ng-model="choice.item_name"/>
</div>
</div>
</td>
<td>
<div class="form-group">
<div class="input-group">
<select data-ng-options='t.value as t.label for t in vm.invoice_item_type' ng-model="choice.item_type" >
</select>
</div>
</div>
</td>
contoller
vm.choices = [];
vm.addNewChoice = function() {
var newItemNo = parseInt(vm.choices.length+1);
vm.choices.push({});
};
vm.saveChoice = function() {
var lastItem = vm.choices.length-1;
------ What to do here ------
};
Ok, the easiest way to do this would be probably something like this:
Add additional field to every choice object saying if it's saved or not
Add two <td>s for every choice, one with plain text and one with input and show/hide them depending on extra parameter' value.
Something like this:
<tr class="odd gradeX" ng-repeat="choice in vm.choices">
<td>Add</td>
<td>save</td>
<td ng-hide="choice.saved">
<div class="form-group">
<div class="input-group">
<input type="text" placeholder="Item Name" class="form-control" ng-model="choice.item_name"/>
</div>
</div>
</td>
<td ng-show="choice.saved">
<div class="form-group">
<div class="input-group">
<input type="text" placeholder="Item Name" class="form-control" ng-model="choice.item_name"/>
</div>
</div>
</td>
<!-- rest of your row goes here -->
</tr>
And in controller:
vm.choices = [];
vm.addNewChoice = function() {
var newItemNo = parseInt(vm.choices.length+1);
vm.choices.push({}); // we don't need to set `saved` property explicitly since undefined will be resolved to false
};
vm.saveChoice = function(choice) {
var lastItem = vm.choices.length-1;
choice.saved=true;
// probably some extra logic related to saving
};
Note that I've added parameter to saveChoice method - you need to know which choice to save.
Also, I think that button for adding new choice should be moved outside of the table - adding new item is not related to any existing item.

Knockout foreach bound to value in inputfield

I want to autogenerate a number of labels on the bottom of my page based on what someone fills in in an inputfield.
So when someone fills in "2", I want 2 labels to pop up, preferable when he typed it without leaving the inputfield or anything.
This is what I have:
HTML
<div class="form-group">
<label class="control-label" for="if_aantalMensen">
Hoeveel extra mensen wil je inschrijven?
</label>
<div>
<input type="text" class="form-control" id="if_aantalMensen" name="if_aantalMensen"
data-bind="textInput: aantalMensen">
</div>
</div>
<div data-bind="foreach: aantalMensenArray" class="form-group">
<label><span data-bind="text: $index"></span></label>
</div>
Javascript
var vm = {
aantalMensen: ko.observable(0),
aantalMensenArray: ko.computed(function() {
var fields = [];
for (var i = 0; i < self.selectedNumberOfFields(); i++) {
fields.push(new Parameter());
}
return fields;
})}
It works if I just make "aantalMensenArray" into an observableArray that already has values in it. However, I can't get it to change the amount of labels shown.
Use valueUpdate:'afterkeydown'
"http://jsfiddle.net/dpa6zk9j/"

Categories