I want to make a button that adds and removes items.
The 'Delete form' button changes to 'Add form' after click it.
But after I've deleted and added forms, I want to delete forms again, but for reasons I don't understand, it doesn't happen.
I'm using the latest chrome browser version.
<!DOCTYPE html>
<html lang="en" style="height: 100%">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<title>Task 1</title>
</head>
<body style="height: 100%">
<div class="container h-100">
<div class="row h-100 justify-content-center align-content-center">
<div class=""><button type="button" class="btn btn-primary">Open Google</button></div>
<div class=""><button type="button" class="btn btn-danger" id="danger">Delete form</button></div>
<div class="breaker w-100" style="height:10%;"></div>
<form id="form">
<div class="form-group">
<label for="formGroupExampleInput">Example label</label>
<input type="text" class="form-control" id="formGroupExampleInput" placeholder="Example input">
</div>
<div class="form-group">
<label for="formGroupExampleInput2">Another label</label>
<input type="text" class="form-control" id="formGroupExampleInput2" placeholder="Another input">
</div>
</form>
</div>
</div>
<script src="./index.js"></script>
</body>
</html>
document.getElementsByClassName('btn-primary')[0].addEventListener("click", open_google);
document.getElementsByClassName('btn-danger')[0].addEventListener("click", delete_function);
let inner_form = document.getElementById('form').innerHTML;
function open_google() {
window.open('http://google.com', '_blank');
}
let buttons;
function button_change(button) {
switch(button) {
case "success":
buttons = document.getElementsByClassName('btn');
buttons[1].innerHTML = 'Add form';
buttons[1].className = 'btn btn-success';
document.getElementsByClassName('btn-success')[0].addEventListener("click", add_function);
break;
case "danger":
buttons = document.getElementsByClassName('btn');
buttons[1].innerHTML = 'Delete form';
buttons[1].className = 'btn btn-danger';
break;
default:
break;
}
}
function delete_function() {
let element = document.getElementById('form');
while (element.firstChild) {
element.removeChild(element.firstChild);
}
button_change("success");
}
function add_function() {
document.getElementById('form').innerHTML = inner_form;
button_change("danger");
}
Example code: https://codepen.io/anon/pen/xNjPYj
The event listeners aren't being removed, so both functions are being called (potentially multiple times) depending on how many times the buttons are clicked.
Personally, I think it would be easier to create two buttons, each with independent click handlers, and hide/show them according to which one was clicked.
However, to resolve the current issue in your code, you'll need to remove the previous event listener using removeEventListener() before attaching the new one.
Why don't you just hide it? This is much easier
function toggle() {
var element = document.getElementById("form");
if (element.style.display === "none") {
element.style.display = "block";
}
else {
element.style.display = "none";
}
}
<!DOCTYPE html>
<html lang="en" style="height: 100%">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<title>Task 1</title>
</head>
<body style="height: 100%">
<div class="container h-100">
<div class="row h-100 justify-content-center align-content-center">
<div class=""><button type="button" class="btn btn-primary">Open Google</button></div>
<div class=""><button onclick="toggle()" type="button" class="btn btn-danger" id="danger">Delete form</button></div>
<div class="breaker w-100" style="height:10%;"></div>
<form id="form">
<div class="form-group">
<label for="formGroupExampleInput">Example label</label>
<input type="text" class="form-control" id="formGroupExampleInput" placeholder="Example input">
</div>
<div class="form-group">
<label for="formGroupExampleInput2">Another label</label>
<input type="text" class="form-control" id="formGroupExampleInput2" placeholder="Another input">
</div>
</form>
</div>
</div>
</body>
</html>
The main issue with your code was that the event listeners kept getting added but not removed, this caused them to pile up and run unpredictably. I added a function that determines what state the button is in and performs the correct function add_function or remove_function.
I also changed a few minor things
Now usesinnerHTML to textContent where possible for security
Button classes are updated using button.classList.add and button.classList.remove
The button is found using an ID instead of an unreliable classname
The button is held in a variable instead of continuing the look for it
Removed the button_change function because it was difficult to refactor
https://codepen.io/anon/pen/BexJZW
JavaScript:
document.getElementsByClassName('btn-primary')[0].addEventListener("click", open_google);
let inner_form = document.getElementById('form').innerHTML;
let add_delete_button = document.querySelector('#add-delete-button');
add_delete_button.addEventListener("click", on_add_delete_clicked);
function open_google() {
window.open('http://google.com', '_blank');
}
function on_add_delete_clicked() {
let is_adding = add_delete_button.classList.contains("btn-success");
if (is_adding) {
add_function();
} else {
delete_function();
}
}
function add_function() {
const button = add_delete_button;
document.getElementById('form').innerHTML = inner_form;
// Update button
button.textContent = 'Delete form';
button.classList.remove("btn-success");
button.classList.add("btn-danger");
}
function delete_function() {
let element = document.getElementById('form');
while (element.firstChild) {
element.removeChild(element.firstChild);
}
// Update button
const button = add_delete_button;
button.textContent = 'Add form';
button.classList.remove("btn-danger");
button.classList.add("btn-success");
}
HTML:
<!DOCTYPE html>
<html lang="en" style="height: 100%">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<title>Task 1</title>
</head>
<body style="height: 100%">
<div class="container h-100">
<div class="row h-100 justify-content-center align-content-center">
<div class=""><button type="button" class="btn btn-primary">Open Google</button></div>
<div class=""><button type="button" class="btn btn-danger" id="add-delete-button">Delete form</button></div>
<div class="breaker w-100" style="height:10%;"></div>
<form id="form">
<div class="form-group">
<label for="formGroupExampleInput">Example label</label>
<input type="text" class="form-control" id="formGroupExampleInput" placeholder="Example input">
</div>
<div class="form-group">
<label for="formGroupExampleInput2">Another label</label>
<input type="text" class="form-control" id="formGroupExampleInput2" placeholder="Another input">
</div>
</form>
</div>
</div>
<script src="./index.js"></script>
</body>
</html>
This implementation will do the text and context switching you desire.
function action(mouseevent) {
const button = mouseevent.target;
let element = document.getElementById('form');
if(element.firstChild) {
while (element.firstChild) {
element.removeChild(element.firstChild);
}
button.innerHTML = 'Add form';
button.classList.remove('btn-danger');
button.classList.add('btn-success');
} else {
document.getElementById('form').innerHTML = inner_form;
button.innerHTML = 'Delete Form';
button.classList.add('btn-danger');
button.classList.remove('btn-success');
}
}
Related
I'm developing a COVID-19 tracker app so far it works but I'm having issue for when the user search for a country that isn't in the API a error message is suppose to pop up as the else statement, which indeed it does happen. The issue is the message would pop up when a country that's been entered and the API has the info the error message would still pop up. Any advice would help, thank you.
let btn = document.getElementById("submit-btn");
//set variable btn to the html button id
btn.addEventListener("click",()=>{
let text = document.getElementById("input-text").value;
console.log("button was pressed");
//added a event once btn is pressed taking the value of what was typed in the form
fetch('https://api.covid19api.com/summary')
.then((covidData)=>{
return covidData.json();
})
//
.then((getData)=>{
console.log(getData);
console.log("api was contacted");
var content = document.querySelector(".api-data");
var box = content.lastElementChild;
while (box) {
content.removeChild(box);
box = content.lastElementChild;
}
var countriesIndex = 0;
for(var i = 0; i < 185; i++){
if(getData.Countries[i].Country.toLowerCase() == text.toLowerCase()){
countriesIndex = i;
break;
}
else {
var hideData = document.querySelector(".api-data");
hideData.style.display = "none";
alert("No information for that country")
break;
}
}
let data = document.querySelector(".api-data");
data.innerHTML = `<div class="data-boxes">
<div class="country-index">
<span>Covid-19 Cases in ${getData.Countries[countriesIndex].Country}</span>
</div>
<div class="total-data">
<div><p>Total Confirmed</p> ${getData.Countries[countriesIndex].TotalConfirmed}</div>
<div><p>Total Deaths</p> ${getData.Countries[countriesIndex].TotalDeaths}</div>
<div><p>Total Recovered</p> ${getData.Countries[countriesIndex].TotalRecovered}</div>
</div>
<div class="new-data">
<div><p>New Confirmed</p> ${getData.Countries[countriesIndex].NewConfirmed}</div>
<div><p>New Deaths</p> ${getData.Countries[countriesIndex].NewDeaths}</div>
<div><p>New Recovered</p> ${getData.Countries[countriesIndex].NewRecovered}</div>
</div>
</div>`;
})
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://fonts.googleapis.com/css2?family=News+Cycle:wght#400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<div class="container tracker-container">
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="covid-header">Covid-19 Daily Tracker</h1>
<p class="covid-description">A daily tracker of the Covid-19 virus, enter the country in the search bar to recieve the report.</p>
<p class="covid-description">Report is given from the "covid19api" API.</p>
</div>
</div>
<div class="info-box">
<form>
<div class="form-row input-row">
<div class="col-12 form">
<label for="country-input">Enter country's name</label>
<input type="text" class="form-control" id="input-text" value="" required>
<button type="button" class="btn btn-success btn-block" id="submit-btn">Get Statistics</button>
</div>
</div>
</form>
<div class="api-data">
</div>
</div>
</div>
</body>
<script src="tracker.js"></script>
</html>
The else part is replaced. If countriesIndex is not updated from 0 , that means the data is not found.
Fixed Code:
let btn = document.getElementById("submit-btn");
//set variable btn to the html button id
btn.addEventListener("click",()=>{
let text = document.getElementById("input-text").value;
console.log("button was pressed");
//added a event once btn is pressed taking the value of what was typed in the form
fetch('https://api.covid19api.com/summary')
.then((covidData)=>{
return covidData.json();
})
//
.then((getData)=>{
console.log(getData);
console.log("api was contacted");
var content = document.querySelector(".api-data");
var box = content.lastElementChild;
while (box) {
content.removeChild(box);
box = content.lastElementChild;
}
var countriesIndex = 0;
for(var i = 0; i < 185; i++){
if( getData.Countries[i].Country.toLowerCase() == text.toLowerCase()){
countriesIndex = i;
break;
}
}
if(countriesIndex==0) {
var hideData = document.querySelector(".api-data");
hideData.style.display = "none";
alert("No information for that country")
}
else{
let data = document.querySelector(".api-data");
data.innerHTML = `<div class="data-boxes">
<div class="country-index">
<span>Covid-19 Cases in ${getData.Countries[countriesIndex].Country}</span>
</div>
<div class="total-data">
<div><p>Total Confirmed</p> ${getData.Countries[countriesIndex].TotalConfirmed}</div>
<div><p>Total Deaths</p> ${getData.Countries[countriesIndex].TotalDeaths}</div>
<div><p>Total Recovered</p> ${getData.Countries[countriesIndex].TotalRecovered}</div>
</div>
<div class="new-data">
<div><p>New Confirmed</p> ${getData.Countries[countriesIndex].NewConfirmed}</div>
<div><p>New Deaths</p> ${getData.Countries[countriesIndex].NewDeaths}</div>
<div><p>New Recovered</p> ${getData.Countries[countriesIndex].NewRecovered}</div>
</div>
</div>`;
}
})
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://fonts.googleapis.com/css2?family=News+Cycle:wght#400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<div class="container tracker-container">
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="covid-header">Covid-19 Daily Tracker</h1>
<p class="covid-description">A daily tracker of the Covid-19 virus, enter the country in the search bar to recieve the report.</p>
<p class="covid-description">Report is given from the "covid19api" API.</p>
</div>
</div>
<div class="info-box">
<form>
<div class="form-row input-row">
<div class="col-12 form">
<label for="country-input">Enter country's name</label>
<input type="text" class="form-control" id="input-text" value="" required>
<button type="button" class="btn btn-success btn-block" id="submit-btn">Get Statistics</button>
</div>
</div>
</form>
<div class="api-data">
</div>
</div>
</div>
</body>
<script src="tracker.js"></script>
</html>
I have a step-wizard form with multiple panels within it, I would like to stay on the same panel after I submit using php. Lets say I am on step 2 and submit, I want it to stay on step2(panel 2)
I have tried but when I submit the page loads and it takes me back to step 1(panel 1) instead of staying on step 2(panel 2). How can I solve this?
Bellow is my code
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">
<!-- Bootstrap core CSS -->
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.7.1/css/bootstrap-datepicker3.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.7.1/css/bootstrap-datepicker.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.7.1/js/bootstrap-datepicker.min.js"></script>
</head>
<body>
<div class="container">
<ul class="nav nav-pills nav-wizard">
<li class="active"><span class="nmbr">1</span>Verification</li>
<li><span class="nmbr">2</span>Form</li>
</ul>
<form action="stack.html" method="post" enctype="multipart/form-data" >
<div class="panel panel-borderless setup-content" id="step-1" style="margin-top:8px">
<label style="font-weight:normal">Code:</label>
<input type="string" name="code" />
<label style="font-weight:normal">Name:</label>
<input type="text" name="name" />
<button class="btn btn-primary nextBtn pull-right" type="button" name="next1" onclick="nextPrev(1)">Next</button>
</div>
<div class="panel panel-borderless setup-content" id="step-2" style="margin-top:8px">
<label style="font-weight:normal">item Code:</label>
<input type="string" name="itemcode" />
<label style="font-weight:normal">item Name:</label>
<input type="string" name="itemname" />
<button class="btn btn-primary nextBtn pull-right" type="submit" name="add">add</button>
</div>
</form>
<script>
$(document).ready(function () {
var navListItems = $('.nav-wizard li a'),
allWells = $('.setup-content'),
allNextBtn = $('.nextBtn');
dis = $('#step-1');
allWells.hide();
dis.show();
navListItems.click(function (e) {
e.preventDefault();
var $target = $($(this).attr('href')),
$item = $(this);
if (!$item.hasClass('disabled')) {
navListItems.removeClass('btn-success').addClass('btn-default');
$item.addClass('btn-success');
allWells.hide();
$target.show();
$target.find('input:eq(0)').focus();
}
});
allNextBtn.click(function () {
var curStep = $(this).closest(".setup-content"),
curStepBtn = curStep.attr("id"),
nextStepWizard = $('.nav-wizard li a[href="#' + curStepBtn + '"]').parent().next().children("a"),
curInputs = curStep.find("input[type='text'],input[type='url']"),
isValid = true;
$(".form-group").removeClass("has-error");
for (var i = 0; i < curInputs.length; i++) {
if (!curInputs[i].validity.valid) {
isValid = false;
$(curInputs[i]).closest(".form-group").addClass("has-error");
}
}
if (isValid)
nextStepWizard.removeAttr('disabled').trigger('click');
});
$('.nav-wizard li a.btn-success').trigger('click');
});
</script>
</div>
</body>
</html>
Thank you
I am learning vue and one of the things I would like to do is to clone elements. I was playing with this code:
var multiple = new Vue({
el: '#vue',
data: {
},
methods: {
cloneWidget(e) {
let widgets = document.getElementById('widgets');
let widget = document.getElementById('widget');
clone = widget.cloneNode(true);
clone.id = Math.round(Math.random()*100);
widgets.appendChild(clone);
},
deleteClone(e) {
e.target.parentNode.remove();
}
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="styles.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
</head>
<body>
<h1>Cloning</h1>
<div id="vue">
<form #submit.prevent>
<div id="widgets">
<div id="widget">
<div>
<label for="field1">Field 1:</label>
<input type="text" name="field1">
</div>
<div>
<label for="field2">Field 2:</label>
<input type="text" name="field2">
</div>
<i class="material-icons delete" #click="deleteClone">delete</i>
</div>
</div>
<button #click="cloneWidget">Add Widget</button>
</form>
</div>
<script src="app.js"></script>
</body>
</html>
However, the deleteClone method never gets called outside the original div="widget".
I can't seem to figure out why the event listener is not getting attached to the clones. Will cloneNode() mess up Vue?
With Vue, generally you want to think in terms of data. Here is your example revised, such that a widget is rendered for each object in the widgets array.
In this case, the contents of the array don't make much sense; you would probably want to the properties of each object in the array to match your input fields, but this is just an example to get you going.
var multiple = new Vue({
el: '#vue',
data: {
widgets:[{}]
},
methods: {
addWidget() {
this.widgets.push({})
},
removeWidget(widget) {
this.widgets.splice(this.widgets.findIndex(w => w === widget), 1)
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css" rel="stylesheet"/>
<h1>Cloning</h1>
<div id="vue">
<form #submit.prevent>
<div id="widgets">
<div v-for="widget in widgets">
<div>
<label for="field1">Field 1:</label>
<input type="text" name="field1">
</div>
<div>
<label for="field2">Field 2:</label>
<input type="text" name="field2">
</div>
<i class="material-icons delete" #click="removeWidget(widget)">delete</i>
</div>
</div>
<button #click="addWidget">Add Widget</button>
</form>
</div>
For the most part, you want to stay away from manipulating the DOM directly and let Vue do the work for you.
I already have my own solution for this problem, but then I don't know if I'm using the best techniques/practices to solve this particular scenario, which involves removing and adding DOM elements with unique id's.
I have just used jQuery, the requirements where only a button to add any amount of rows, once another row is added be able to delete that row too, the first row is always mandatory, here is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> <title>Simple form</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<style type="text/css">
label{
display: block;
}
</style>
</head>
<body>
<div class="container">
<div class="row inputRows">
<div class="col-sm-12" id="newRow-1">
<label>Some label over input</label>
<input type="text" name="txt">
</div>
</div>
<div class="row">
<div class="col-sm-12">
<button id="addRow"><span class="fa fa-plus"></span> Add </button>
<button id="viewInfo"><span class="fa fa-plus"></span> Info </button>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<p id="result">
</p>
</div>
</div>
</div>
<script src="https://npmcdn.com/tether#1.2.4/dist/js/tether.min.js"></script>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
<script type="text/javascript">
$('.inputRows').on('click', 'button' ,function(){
$(this).parent().remove();
});
$('#addRow').click(function(){
var $newRow = $('div[id^="newRow"]:first').clone(),
newId = Number($('div[id^="newRow"]:last').attr('id').split('-')[1]) + 1;
$newRow.append('<button><span class="fa fa-trash-o"></span></button>');
$newRow.find('input').val('');
$newRow.attr('id','newRow-' + newId);
$('.inputRows').append($newRow);
});
$('#viewInfo').click(function(){
$('#result').text(JSON.stringify(objectifyForm($('div[id^="newRow"]'))));
});
function objectifyForm(formArray) {
var resultArray = {},
inputValue = '';
for (var i = 0; i < formArray.length; i++){
inputValue = $(formArray[i]).find('input').val();
if(inputValue){
resultArray[$(formArray[i]).attr('id')] = inputValue;
}
}
return resultArray;
}
</script>
</body>
</html>
So the code works, the only problem I see is that the numeration of the id's, can sometimes be 1,5,8,7,6,12 depending on which ones you delete, but then it's fine because in the end, it doesn't even matter (joke, RIP Chester, but kind of true). My main concern or question is, is there any other way of achieving this more efficiently using jQuery? Am I doing something wrong by cloning the first element multiple times? If you can share some knowledge on DOM manipulation that would be great.
Thanks in advance,
Leo.
This is my controller from which I am requesting to POST the data on server. While I am able to POST title and rating, i am unable to POST any genres because Genres is an array. How to push the data in Genres Array?
app.controller('addTrack', function ($scope, $http) {
$scope.tracks = [];
var genre = [];
var pushing = genre.push($scope.add_genre);
$scope.add_track = "";
$http.get('http://104.197.128.152:8000/v1/tracks?page=48')
.then(function (response) {
$scope.tracks = response.data.results;
});
$scope.add = function (event) {
if (event.keyCode == 13) {
$http.post('http://104.197.128.152:8000/v1/tracks', {
title: $scope.add_title,
rating: $scope.add_rating,
})
.then(function (data) {
$scope.genres = data;
//console.log($scope.add_genre);
$scope.add_title = '';
$scope.add_rating = '';
$scope.add_genre = '';
});
$http.get('http://104.197.128.152:8000/v1/tracks?page=48')
.then(function (response) {
$scope.genres = response.data.results;
});
}
} });
Http POST to http://104.197.128.152:8000/v1/tracks
Accepted response
{
"title": "animals",
"rating": 4.5,
"genres": [
1
]
}
Providing you my HTML as well.
<!DOCTYPE html>
<html ng-app="musicApp">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div class="container" ng-controller="addTrack">
<div>
<h1>Add New Track</h1>
</div>
<div class="form-group">
<label>Title:</label>
<input type="text" class="form-control" ng-model="add_title" placeholder="Type to add new Title">
</div>
<div class="form-group">
<label>Genre:</label>
<input type="text" class="form-control" ng-model="add_genre" placeholder="Type to add new Genre">
</div>
<div class="form-group">
<label>Rating:</label>
<input type="text" class="form-control" ng-model="add_rating" placeholder="Type to add new Rating" ng-keyup="add($event)">
</div>
<div class="clearfix">
<button class="btn btn-primary col-xs-12 bottom-button" value="click" id="button">Add a New Track</button>
</div>
<div class="clearfix">
<label>Available Tracks</label>
<ul class="list-group" ng-repeat="track in tracks">
<li class="list-group-item clearfix"><span class="pull-left title">{{track.title}}</span> <span class="genre">[{{track.genres[0].name}}]</span> <span class="pull-right rating">{{track.rating}}</span></li>
</ul>
</div>
</div>
</body>
</html>
If what you are trying to achieve is to add a track object with title, rating and genre, you need to change your whole logic so your controller will bind all inputs to the same object properties.
First you need to define a track object in your controller, and bind the inputs to its properties in your HTML:
JavaScript:
app.controller('addTrack', function($scope, $http) {
$scope.tracks = [];
$scope.track = {
title: '',
rating: 0,
genre: ''
};
$http.get('http://104.197.128.152:8000/v1/tracks?page=48')
.then(function(response) {
$scope.tracks = response.data.results;
});
$scope.add = function(event) {
if (event.keyCode == 13) {
$http.post('http://104.197.128.152:8000/v1/tracks', $scope.track)
.then(function(data) {
$scope.track = {};
});
}
}
});
HTML:
<!DOCTYPE html>
<html ng-app="musicApp">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div class="container" ng-controller="addTrack">
<div>
<h1>Add New Track</h1>
</div>
<div class="form-group">
<label>Title:</label>
<input type="text" class="form-control" ng-model="track.title" placeholder="Type to add new Title">
</div>
<div class="form-group">
<label>Genre:</label>
<input type="text" class="form-control" ng-model="track.genre" placeholder="Type to add new Genre">
</div>
<div class="form-group">
<label>Rating:</label>
<input type="text" class="form-control" ng-model="track.rating" placeholder="Type to add new Rating" ng-keyup="add($event)">
</div>
<div class="clearfix">
<button class="btn btn-primary col-xs-12 bottom-button" value="click" id="button">Add a New Track</button>
</div>
</div>
</body>
</html>
Note:
Note the use of ng-model="track.title", ng-model="track.rating"
and ng-model="track.genre" in the HTML to bind these inputs to our
trackobject properties.
This code assumes that genre will be a string here, if you will use a
list of object you need to amend your code so it fits this option.