Have a form to create a contract, where that contract can have one or more users associated.
The area to input the users info, starts with only one field of one user, and one button to add more fields if needed.
<div id="utilizadores" class="row">
<div id="utilizador1" class="container-fluid">
<div class="row">
<div class="col-lg-5">
<input type="text" class="form-control" id="nomeUtilizador1" placeholder="Nome Utilizador">
</div>
<div class="col-lg-6">
<input type="text" class="form-control" id="funcaoUtilizador1" placeholder="Função">
</div>
</div>
</div>
</div>
This is the starting div
Clicking on Add User button it adds a new div under the "utilizador1"
<div id="utilizadores" class="row">
<div id="utilizador1" class="container-fluid">
<div class="row">
<div class="col-lg-5">
<input type="text" class="form-control" id="nomeUtilizador1" placeholder="Nome Utilizador">
</div>
<div class="col-lg-6">
<input type="text" class="form-control" id="funcaoUtilizador1" placeholder="Função">
</div>
</div>
</div>
<div id="utilizador2" class="container-fluid">
<div class="row">
<div class="col-lg-5">
<input type="text" class="form-control" id="nomeUtilizador2" placeholder="Nome Utilizador">
</div>
<div class="col-lg-6">
<input type="text" class="form-control" id="funcaoUtilizador2" placeholder="Função">
</div>
</div>
</div>
My question is, how can I get the number of users created, and insert them into a list using Javascript. The list will be a attribute of a Object (Contract).
What i have til now:
function test_saveItem() {
var contract = new Object();
contract.Dono = <% =uID %>;
contract.BoostMes = $("#boostMes").val();
contract.BoostAno = $("#boostAno").val();
var ListaUtilizadores = [];
var divs = document.getElementsByName("utilizador");
for (var i = 0; i < divs.length; i++){
var user = new Object();
user.Nome = $('#nomeUtilizador' + i).val();
ListaUtilizadores.push(user);
}
var test = JSON.stringify({ "contract": contract });
}
Any help appreciated
Edit: Got to a solution thanks to Shilly
List = [];
Array.prototype.slice.call(document.querySelectorAll('.user')).forEach(function (node, index) {
List.push({
"name" : document.getElementById('nameUser' + (index + 1)).value,
"job" : document.getElementById('jobUser' + (index + 1)).value
});
});
Something like this? But adding it into the addUser function as Super Hirnet says, will be more performant.
var divs = document.querySelector('#utilizadores').childNodes,
users = [];
Array.slice.call(divs).forEach(function (node, index) {
users.push({
"name" : divs[index].getElementById('nomeUtilizador' + (index + 1)).value
});
});
You can have an empty array and on every click of addUser put a new object into the array. The object can have information related to the added user.
Related
Currently experimenting with JavaScript and building a To-Do List Web App. Having some issues with it. When I refresh the page, it gives the error:
TypeError: tasks is null
And when I press the submit button, it gives the error:
TypeError: cyclic object value
I was trying it out after reading a tutorial online on JavaScript and then I got the idea on implementing it with some basic project like this one.
How can I resolve the errors? I can't seem to figure out the solution.
JS Code:
document.getElementById('form-Task').addEventListener('submit', saveTask);
// Save new To-Do Item
function saveTask(e){
let title = document.getElementById('title').value;
let description = document.getElementById('description').value;
let task = {
title,
description
};
if(localStorage.getItem('tasks') === null) {
let = tasks = [];
tasks.push(tasks);
localStorage.setItem('tasks', JSON.stringify(tasks));
} else {
let tasks = JSON.parse(localStorage.getItem('tasks'));
tasks.push(task);
localStorage.setItem('tasks', JSON.stringify(tasks));
}
getTasks();
// Reset form-Task
document.getElementById('form-Task').reset();
e.preventDefault();
}
// Delete To-Do Item
function deleteTask(title) {
let tasks = JSON.parse(localStorage.getItem('tasks'));
for (let i = 0; i < tasks.length; i++){
if(tasks[i].title == title) {
tasks.splice(i, 1);
}
}
localStorage.setItem('tasks', JSON.stringify(tasks));
getTasks();
}
// Show To-Do List
function getTasks(){
let tasks = JSON.parse(localStorage.getItem('tasks'));
let tasksView = document.getElementById('tasks');
tasksView.innerHTML = '';
for(let i = 0; i < tasks.length; i++){
let title = tasks[i].title;
let description = tasks[i].description;
tasksView.innerHTML +=
`<div class="card mb-3">
<div class="card-body">
<div class="row">
<div class="col-sm-3 text-left">
<p>${title}</p>
</div>
<div class="col-sm-7 text-left">
<p>${description}</p>
</div>
<div class="col-sm-2 text-right">
X
</div>
</div>
</div>
</div>`;
}
}
getTasks();
HTML code:
<nav class="navbar navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="#">My To-Do List</a>
</div>
</nav>
<div class="container">
<div class="row my-5">
<div class="col-md-4">
<div class="card">
<div class="card-body">
<form id="form-Task">
<div class="form-group">
<input type="text" id="title" class="form-control" maxlength="50" autocomplete="off" placeholder="Title" required>
</div>
<div class="form-group">
<textarea type="text" id="description" cols="30" rows="10" class="form-control" maxlength="500" autocomplete="off" placeholder="Description" required></textarea>
</div>
<button type="submit" class="btn btn-success btn-block">Save</button>
</form>
</div>
</div>
</div>
<div class="col-md-8">
<div class="row">
<div class="col-sm-3 text-left">
<p class="font-weight-bold">Title</p>
</div>
<div class="col-sm-6 text-left">
<p class="font-weight-bold">Description</p>
</div>
<div class="col-sm-3 text-right">
<p class="font-weight-bold">Delete</p>
</div>
</div>
<hr>
<div id="tasks"></div>
</div>
</div>
</div>
<script src="js/app.js"></script>
I am still learning javascript so I might have missed something, but in your first if statement, you have an extra "=":
if(localStorage.getItem('tasks') === null) {
let = tasks = []; // let tasks = []
tasks.push(tasks);
and I am not sure about that first definition of the task variable. With curly braces, you make key-value pairs, but you didn't add the value. For example:
var person = { firstName: "John", lastName: "Doe" };
Hope I helped.
In the form I am making, there is a section that requires users to enter the amount of people in their family. After they provide it, the form generates enough input fields so that the user can enter information for each family member.
What I am having trouble with is none of the attributes that I am trying to apply to the input element actually work.
function addHouseMembers(that){
var family = document.getElementById("family-input-container");
while(family.hasChildNodes()){
family.removeChild(family.lastChild);
}
for(var i = 1; i < that.value; i++){
family.appendChild(document.createTextNode("Family Member " + (i+1)));
family.appendChild(document.createElement("br"));
//name
family.appendChild(document.createTextNode("Name: " ));
var input = document.createElement("input");
input.type = "text";
input.name = "member" + i + "_name";
input.pattern = "/^[a-zA-Z ]*$/";
input.required = true;
family.appendChild(input);
family.appendChild(document.createElement("br"));
}
}
The parameter that refers to the input where the user would put in the number of people in their family.
And here is the relevant HTML:
<form>
<div class="form-group">
<label class="col-lg-3 control-label">What is the total amount of people living in your household?</label>
<div class="col-lg-3 inputGroupContainer">
<div class = "input-group">
<input type="text" class="form-control" name="household-size" required onchange="addHouseMembers(this);"/>
</div>
</div>
</div>
<div class="form-group", id="family-info">
<label class="col-lg-12">Information for other Family Members</label>
<div class="col-lg-3 inputGroupContainer">
<div class = "input-group" id = "family-input-container" required>
</div>
</div>
</div>
</form>
The element shows up as it should, and is submitted with the form when the user hits the submit button, but the regex pattern and required attributes are not enforced.
in addHouseMembers(that) the value of that is a string, not a number, and you have to check if is value can be 'translated' in an integer value.
use the "onchange" event on the input field household-size is not a good idea because this event is triggered each time a digit of the number entered, which has the effect of erasing and completely rewrite the family-input-container part
I Imagine you are looking for something like that ?
const myForm = document.getElementById('my-form')
, familyElm = document.getElementById('family-input-container')
, parserDOM = new DOMParser()
;
function newHouseMember(ref)
{
let div=
` <div>
Family Member ${ref}<br>Name: <br>
<input type="text" name="member${ref}_name" pattern="/^[a-zA-Z ]*$/" required >
</div>`
return parserDOM.parseFromString( div, 'text/html').body.firstChild
}
myForm.btPeoples.onclick=_=>
{
let nbPeoples = parseInt(myForm['household-size'].value)
if (!isNaN(nbPeoples) && nbPeoples > 0 )
{
familyElm.innerHTML = ''
for (let i=1; i<=nbPeoples; i++)
{
familyElm.appendChild( newHouseMember(i) )
}
}
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" >
<form id="my-form">
<div class="form-group">
<label class="col-lg-3 control-label">What is the total amount of people living in your household?</label>
<div class="col-lg-3 inputGroupContainer">
<div class = "input-group">
<input class="form-control" name="household-size" required value="" placeholder="number of peoples" pattern="\d*" />
<button name="btPeoples" class="btn btn-info" type="button" >check it!</button>
</div>
</div>
</div>
<div class="form-group", id="family-info">
<label class="col-lg-12">Information for other Family Members</label>
<div class="col-lg-3 inputGroupContainer">
<div class="input-group" id="family-input-container">
</div>
</div>
</div>
</form>
I have an observable array that contains a list of object that I want to filter through based on a user input. If the user searches a word that appears in the array in two different places then the filter function should return the title of both objects and delete or hide all other objects in the array that did not match the input from the user. I must use knockout js to preform this feature which is still new to me. Currently my filter function checks to see if the user input is included in a title of one of the objects within the array and if it is not then it removes the object. However, this not providing me what I need as it does not accurately filter the list.
My ViewMode
var viewModel = function() {
var self = this;
self.filter = ko.observable('');
self.locationList = ko.observableArray(model);
self.filterList = function(){
return ko.utils.arrayFilter(self.locationList(), function(location) {
if(location.title == self.filter()){
return location.title
}
else if( location.title.includes(self.filter()) ){
return location.title
}
else{
return self.locationList.remove(location)
}
});
};
}
The View
<section class="col-lg-2 sidenav">
<div class="row">
<div class="col-lg-12">
<div class="input-group">
<input data-bind="textInput: filter"
type="text" class="form-control" placeholder="Filter Places"
aria-describedby="basic-addon2" id="test">
<button data-bind="click: filterList id="basic-addon2">
<i class="glyphicon glyphicon-filter"></i>
Filter
</button>
</div>
</div>
<div class="col-lg-12">
<hr>
<div data-bind="foreach: locationList">
<p data-bind="text: $data.title"></p>
</div>
</div>
</div>
</section>
The answer to the question can be found here answered by Viraj Bhosale
ViewModel
var viewModel = function() {
var self = this;
self.filter = ko.observable('');
self.locationList = ko.observableArray(model);
self.filterList = ko.computed(function(){
return self.locationList().filter(
function(location){
return (self.filter().length == 0 || location.title.toLowerCase().includes(self.filter().toLowerCase()));
}
);
});
}
View
<main class="container-fluid">
<div class="row">
<section class="col-lg-2 sidenav">
<div class="row">
<div class="col-lg-12">
<div class="input-group">
<input data-bind="textInput: filter, valueUpdate: 'keyup'"
type="text" class="form-control" placeholder="Filter Places"
aria-describedby="basic-addon2" id="test">
</div>
</div>
<div class="col-lg-12">
<hr>
<div data-bind="foreach: filterList">
<p data-bind="text: $data.title"></p>
</div>
</div>
</div>
</section>
<section class="col-lg-10" id="map"></section>
</div>
Here's what I need to do.
I need to create an array of array of objects like the format below. I am getting name and values of input boxes and put then in a json then push it in an array and then I push the generated array into another array.
[
[
{"key1":"value1","key2":"value2"},
{"key1":"value3","key2":"value4"},
],
[
{"key1":"value1","key2":"value2"},
{"key1":"value1","key2":"value2"},
]
]`
below is my code
$scope.saveImages = function(){
var arrayOfArrays =[];
var arrayOfPhotos = [];
angular.element('.photo-group').each(function(){
var object = {};
$(this).find('.photo').each(function(){
var key = $(this).attr('name');
var value = $(this).val();
object[key] = value;
});
arrayOfPhotos.push(object)
arrayOfArrays.push(arrayOfPhotos)
console.log(arrayOfArrays)
});
}
and this is my markup
<div class="photo-group">
<div class="photo-group-body">
<div class="initial-photo">
<div class="row no-padding new-photo">
<div class="col no-padding">
<div class="form-group no-right-padding">
<label class="label-control" class="label-control">Label</label>
<input type="text" name="photo_label" class="form-control photo">
<input type="text" name="image_data" class="form-control photo photo_data">
</div>
</div>
</div>
</div>
<div class="initial-photo">
<div class="row no-padding new-photo">
<div class="col no-padding">
<div class="form-group no-right-padding">
<label class="label-control" class="label-control">Label</label>
<input type="text" name="photo_label" class="form-control photo">
<input type="text" name="image_data" class="form-control photo photo_data">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="photo-group">
<div class="photo-group-body">
<div class="initial-photo">
<div class="row no-padding new-photo">
<div class="col no-padding">
<div class="form-group no-right-padding">
<label class="label-control" class="label-control">Label</label>
<input type="text" name="photo_label" class="form-control photo">
<input type="text" name="image_data" class="form-control photo photo_data">
</div>
</div>
</div>
</div>
</div>
</div>
In my markup I have two .photo-group classes.
on the first .photo-group class I have four .photo class
and on the second .photo-group class I have two .photo class
so my array should look like this
[
[
{"photo_label":"value1", "image_data":"value2"},
{"photo_label":"value3", "image_data":"value4"},
],
[
{"photo_label":"value4", "image_data":"value5"},
]
]`
but instead, what I get is only the last objects in each array
[
[
{"photo_label":"value3", "image_data":"value4"},
],
[
{"photo_label":"value4", "image_data":"value5"},
]
]`
creat the pushing object inside foreach
angular.element('.photo-group').each(function(){
$(this).find('.photo').each(function(){
var object = {};
var key = $(this).attr('name');
var value = $(this).val();
object[key] = value;
arrayOfPhotos.push(object);
});
arrayOfArrays.push(arrayOfPhotos);
console.log(arrayOfArrays);
});
So after hours of trial and error testing and tracing the flow of the code.. I was able to get what I want.
Here's what I did
$scope.saveImages = function(){
var arrayOfArrays =[];
angular.element('.photo-group').each(function(){
var arrayOfPhotos = [];
$(this).find('.initial-photo').each(function(){
var object = {};
$(this).find('.photo').each(function(){
var key = $(this).attr('name');
var value = $(this).val();
object[key] = value;
});
arrayOfPhotos.push(object)
});
arrayOfArrays.push(arrayOfPhotos);
});
}
I added another loop to go deep into the child elements and place the var arrayOfPhotos = []; in the first instance of the loop
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;
}
};