Sending a post request via ajax is not working - javascript

I want to send an Ajax request when clicking a button but it seems my request is never executed.
Here is my HTML code :
<!DOCTYPE html>
<html lang="en">
<head>
<title>User Form</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script src = "./actions.js"></script>
</head>
<body>
<div id="badFrm" class="container">
<h2><br>User Registration</h2>
<form id="Form" method="post">
<div class="form-group">
<label for="name">Name:</label>
<input type="name" class="form-control" id="name" placeholder="Enter Name" name="name">
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" class="form-control" id="email" placeholder="Enter Email" name="email">
</div>
<button id="submitBtn" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>
and here is my javascript code :
i feel there is something wrong with my javascript code but i cant figure whats wrong ! i changed a lot of it based on the comments . what i want is when i click on the update button it changes to " submit again " and i want to replace "list items" ( name and eamil ) with input fields and put whatever written in them to be saved in the database instead . and eventually return to the first page which is the register form.
$(document).ready(function() {
var i ;
$("#submitBtn").click(function (e) {
e.preventDefault();
var name = $("#name").val();
var email = $("#email").val();
$.post("http://localhost/MiniProject/connect.php",
{
name: name,
email: email
}, function () {
var element = document.getElementById("badFrm");
element.remove();
showTbl();
});
function showTbl() {
$.post("http://localhost/MiniProject/Select.php",
{
name: name,
email: email
}, function (res) {
// console.log(res);
res = JSON.parse(res);
var html = '<ul id="List">';
for (i = 0; i < res.length; i++) {
var j = i +1 ;
html += '<li class = "name" >' + res[i].name + '</li><li class = "email">' + res[i].email + '</li>'+ '<div>' + '<button onclick="removeUser(this)" id="'+j+'" class="btn btn-primary">Remove</button>' + '<button onclick="updateUser(this)" id="'+j+'" class="btn btn-primary">Update</button>' + '</div>';
}
html += '</ul>';
document.body.innerHTML = html;
});
}
// function Update() {
// $.post("http://localhost/MiniProject/Update.php",
// {
// name: name,
// email: email
// }, function (res) {
// alert(res);
// });
// }
});
});
// $(document).ready(function() {
//
// $("#removeBtn").click(function (e) {
// e.preventDefault();
// var ID = document.getElementById("removeBtn");
// var element2 = document.getElementById("List");
// element2.remove();
// $.post("http://localhost/MiniProject/Remove.php",{
// id : ID
// }, function (res) {
// document.write(res);
// });
// });
//
// });
function removeUser(element){
var ID = element.id;
var element2 = document.getElementById();
element2.remove();
$.post("http://localhost/MiniProject/Remove.php",{
id : ID
}, function (res) {
console.log(res);
document.write(res);
});
//alert(element.id);
}
function updateUser(element){ // i need help in this part
var ID2 = element.id;
listItem = document.querySelector("li.name");
newNameInput = document.createElement('INPUT');
newNameInput.innerHTML = '<input type="name" class="form-control" id="name" placeholder="Enter New Name" name="name">';
listItem.parentNode.replaceChild(newNameInput, listItem);
listItem = document.querySelector("li.email");
newEmailInput = document.createElement('INPUT');
newEmailInput.innerHTML = '<input type="email" class="form-control" id="email" placeholder="Enter New Email" name="email">';
listItem.parentNode.replaceChild(newEmailInput, listItem);
// var Data = document.getElementbyId("lstitm");
// Data.remove();
// var Input = document.createElement("INPUT");
// Input.setAttribute('type','text');
$.post("http://localhost/MiniProject/Update.php",{
id : ID2,
}, function (res) {
console.log(res);
// document.write(res);
});
}

The issue is in the javascript code.
I can see that you are creating the button #removeBtn on the callback of the ajax request sent when the user clicks on the submit button, in showTbl().
Then you call removeUser() that is creating the handler for the newly created #removeBtn button.
The issue you are experiencing is that the ajax callback is asynchronous. So, you are attaching the handler on the #removeBtn before the button is created.
Here is what you should do :
$("#submitBtn").click(function (e) {
e.preventDefault();
var name = $("#name").val();
var email = $("#email").val();
$.post("http://localhost/MiniProject/connect.php",
{
name: name,
email: email
}, function () {
var element = document.getElementById("badFrm");
element.remove();
showTbl();
//removeUser(); <- remove that line
// Update();
}
);
function showTbl() {
$.post("http://localhost/MiniProject/Select.php",
{
name: name,
email: email
}, function (res) {
res = JSON.parse(res);
var html = '<ul id="List">';
for (var i = 0; i < res.length; i++) {
html += '<li>' + res[i].name + '</li><li>' + res[i].email + '</li>'+ '<div>' + '<button id="removeBtn" class="btn btn-primary">Remove</button>' + '<button id="updateBtn" class="btn btn-primary">Update</button>' + '</div>';
}
html += '</ul>';
document.body.innerHTML = html;
removeUser(); // <- call it there instead
}
);
}
I also recommend you yo rename your function removeUser() as it is not removing anything, it is just attaching the handler to the button.

Related

how to get and render selected values related data from array in jquery?

I have no expertise in javascript but I want to render this data which is showing in my console.log below
How can I make forloop or something like that to render this data in my html input?
create.html
<div class="col-sm-2">
<div class="form-group">
<label>Expected Values</label>
<input type="text" class="form-control" value="{{vital.expected_values}}" readonly>
</div>
</div>
<div class="col-sm-2">
<div class="form-group">
<label>Price</label>
<input type="text" class="form-control" value="{{vital.price}}" readonly>
</div>
</div>
<script type="text/javascript">
$(document).ready(function () {
$("#id_vitals").change(function () {
var vitals = $(this).val();
$.ajax({
url: $('#personForm').data('url'),
data: { 'vital_id': vitals },
success: function (response) {
console.log(response[vitals['name']])
}
});
});
})
</script>
I would do it somehow like that:
// Your data
let dataArray = [{data: 1, otherData: 2, elseData: 3}]
// The element, where you want to show it
let targetElement = document.getElementById('your-targer-id');
// The container element for elements
let newContainer = document.createElement('ul');
// Pure JS loop, easy to understand what is happening
// But you can also do it with .map();
for (let i = 0; i < dataArray.length; i++) {
// Add every line
newContainer.innerHTML+='<li>' + dataArray[i].data + '</li>';
// Or other things, depending how you want to show the data
newContainer.innerHTML+='<li> data value is: ' + dataArray[i].data + ' and otherData value is: ' + dataArray[i].otherData + '</li>'; //etc
}
// Append created list in target element
targetElement.appendChild(newContainer);
EDIT - now I see, that you want to display multiple values in text input, rather like so:
let dataArray = [...your-data-array]
let targetElement = document.getElementById('target-input');
for (let i = 0; i < dataArray.lenght; i++) {
// loop throug elements and add it to value attribute of input, separated by coma.
targetElement.value+=dataArray[i].expected_values + ', ';
}

push input to the array list and update content with the new one

It is so that when I write something in my input, do not update my array list with the new content that I have written in input.
I have tried to push into names but it will not add it to the array.
var names = ["Lars", "Peter", "Jan", "Ian"];
var li = names.map(function(names) {
return "<li>".concat(names).concat("</li>")
});
document.getElementById("ul").innerHTML = "<ul>" + li.join("") + "</ul>";
document.getElementById("btn").onclick = addName;
function addName(e) {
var inputVale = document.getElementById("name").value;
names.push(inputVale); //try to push input to names here...
console.log(names);
e.preventDefault();
}
<div id="ul"></div>
<div>
<form>
<input type="text" id="name">
<button id="btn">Add name</button>
</form>
</div>
The problem here is that you are updating the array, but it is not binded to the HTML. To solve this issue you could either use a framework that will bind the HTML to the array (i.e. Angular, React), or you could just manually update the HTML after the button is clicked.
Here is an example:
var names = ["Lars", "Peter", "Jan", "Ian"];
document.getElementById("btn").onclick = addName;
function resetHTML() {
var li = names.map(function(name) {
return "<li>" + name + "</li>";
});
document.getElementById("ul").innerHTML = "<ul>" + li.join("") + "</ul>";
}
function addName(e) {
var inputVale = document.getElementById("name").value;
names.push(inputVale); //try to push input to names here...
console.log(names);
resetHTML();
e.preventDefault();
}
resetHTML();
<div id="ul"></div>
<div>
<form>
<input type="text" id="name">
<button id="btn">Add name</button>
</form>
</div>
You could also use a Proxy (ES6 only) to listen for changes in the array. This way the HTML will automatically get updated whenever the array gets changed.
var names = ["Lars", "Peter", "Jan", "Ian"];
document.getElementById("btn").onclick = addName;
names = new Proxy(names, {
set: function(target, property, value, receiver) {
target[property] = value;
resetHTML();
return true;
}
});
function resetHTML() {
var li = names.map(function(name) {
return "<li>" + name + "</li>";
});
document.getElementById("ul").innerHTML = "<ul>" + li.join("") + "</ul>";
}
function addName(e) {
var inputVale = document.getElementById("name").value;
names.push(inputVale); //try to push input to names here...
console.log(names);
e.preventDefault();
}
resetHTML();
<div id="ul"></div>
<div>
<form>
<input type="text" id="name">
<button id="btn">Add name</button>
</form>
</div>
Your array isn't tied to the elements you display on your screen. At the moment you are simply looping through your array once at the beginning, and then adding your array contents to your HTML.
Instead, you need to update the HTML every time you add a new name such that it is representative of your array. You can do this by creating a function which is responsible for displaying the array content to your HTML. Here I call this function updateHMTL, which accepts an array.
See working example below:
var names = ["Lars", "Peter", "Jan", "Ian"];
document.getElementById("btn").onclick = addName;
function addName(e) {
var inputVale = document.getElementById("name").value;
names.push(inputVale); //try to push input to names here...
updateHTML(names);
e.preventDefault();
}
function updateHTML(names) {
var li = names.map(function(names) {
return "<li>" + names +"</li>";
});
document.getElementById("ul").innerHTML = "<ul>" + li.join("") + "</ul>";
}
updateHTML(names);
<div id="ul"></div>
<div>
<form>
<input type="text" id="name">
<button id="btn">Add name</button>
</form>
</div>
If you wish you can use ES6 syntax (and use .reduce to make your updateHTML function more optimized):
const names = ["Lars", "Peter", "Jan", "Ian"];
const updateHTML = names => {
const ulli = "<ul>" + names.reduce((acc, n) => `${acc}<li>${n}</li>`, "") + "</ul>";
document.getElementById("ul").innerHTML = ulli;
}
const addName = e => {
const inputVale = document.getElementById("name").value;
names.push(inputVale);
updateHTML(names);
e.preventDefault();
}
document.getElementById("btn").onclick = addName;
updateHTML(names);
<div id="ul"></div>
<div>
<form>
<input type="text" id="name">
<button id="btn">Add name</button>
</form>
</div>
You can override push like this:
var ul = document.getElementById("ul");
var names = ["Lars", "Peter", "Jan", "Ian"];
names.push = function() {
Array.prototype.push.apply(this, arguments);
// ... this will execute on each .push
var newLi = document.createElement("li");
newLi.appendChild(document.createTextNode(arguments[0]));
ul.appendChild(newLi);
};
Check complete code on JSFiddle https://jsfiddle.net/Arif2009/67Lm4u8b/22/

Issues with using AJAX and JQuery to multiselect and capture information from JSON file

I have a live search function that parses information from a JSON file using AJAX and jQuery, and then is clickable. What I'm struggling to figure out is how to have the value (in this case, "happy" or "fat") populate a multiselect, and then once that's accomplished, capture the rest of the data in that JSON array to be utilized later.
$(document).ready(function(){
$.ajaxSetup({ cache: false });
$('#search').keyup(function(){
$('#result').html('');
$('#state').val('');
var searchField = $('#search').val();
var expression = new RegExp(searchField, "i");
$.getJSON('coretype.json', function(data) {
$.each(data, function(key, value){
if (value.identifier.search(expression) != -1)
{
$('#result').append('<li class="list-group-item link-class"> '+value.identifier+'</li>');
}
});
});
});
$('#result').on('click', 'li', function() {
var click_text = $(this).text().split('|');
$('#search').val($.trim(click_text[0]));
$("#result").html('');
});
});
I have gotten all the way to having the value be clickable, and have been unsuccessful figuring out the rest from there.
Here's the JSON file:
[
{
"identifier":"Happy",
"progressbar1": 3,
"progressbar2": 2,
"progressbar3": -2
},
{
"identifier":"Fat",
"progressbar1": -3,
"progressbar2": -2,
"progressbar3": 2
}
]
Ideally I'd like javascript to be able to capture the "progressbarX" values when someone types in the identifier, although I figure there's a much easier way to accomplish this...
<!-- Search -->
<br /><br />
<div class="container" style="width:900px;">
<h2 align="center">EnneaTest</h2>
<br /><br />
<div align="center">
<input type="text" name="search" id="search" placeholder="trait type" class="form-control" />
</div>
<ul class="list-group" id="result"></ul>
<br />
</div>
</div>
</div>
Here's the Plunker file
I created a kind of autocomplete drop down for search from json. And once one of the options from that dropdown is selected, I add that to the result list. At that time the whole object is pushed into searchObjects object. When the item from the list is clicked, that text is used to search the object associated with it. Hope this helps..
<!-- Search -->
<br /><br />
<div class="container" style="width:900px;">
<h2 align="center">EnneaTest</h2>
<br /><br />
<div align="center">
<input type="text" name="search" id="search" placeholder="trait type" class="form-control" />
</div>
<div id="searchResult"></div>
<div>
<ul class="list" id="result" style="color: red;"></ul>
</div>
<br />
</div>
<script>
$(document).ready(function(){
$.ajaxSetup({ cache: false });
$('#search').keyup(function(){
var searchField = $('#search').val();
var regex = new RegExp(searchField, "i");
var output = '<div class="row">';
$.getJSON('coretype.json', function(data) {
$.each(data, function(key, val){
if (val.identifier.search(regex) !== -1) {
console.log(val);
var thisVal = JSON.stringify(val);
output += "<h5 onclick='addToList("+thisVal+")'>" + val.identifier + "</h5>";
}
});
output += '</div>';
$('#searchResult').html(output);
});
});
$('#result').on('click', 'li', function() {
var click_text = $(this).text();
console.log(click_text);
var thisObj = [];
thisObj = findObject(click_text);
console.log(thisObj);
});
});
var searchObjs = [];
function addToList(obj) {
//console.log(obj);
$('#result').append('<li class="list-group-item link-class">'+obj.identifier+'</li>');
$('#searchResult').html('');
var item = {};
item ["identifier"] = obj.identifier;
item ["progressbar1"] = obj.progressbar1;
item ["progressbar2"] = obj.progressbar2;
item ["progressbar3"] = obj.progressbar3;
searchObjs.push(item);
console.log(searchObjs);
}
function findObject(identifier) {
var found = 0;
for (var i = 0, len = searchObjs.length; i < len; i++) {
if (searchObjs[i].identifier === identifier) {
return searchObjs[i]; // Return as soon as the object is found
found = 1;
}
}
if(found === 0) {
return null; // The object was not found
}
} ;
</script>

Using Karma Jasmine -how to test do elements and javascript?

Ive been trying for a while to test js and dom elements and finally came across karma which helps to test dom elements. However anything I have so far just doesn't work. Any help would be very much appreciated.
I have been using this tutorial: http://www.bradoncode.com/blog/2015/02/27/karma-tutorial/ but can't get it to work..
js:
window.calculator = window.calculator || {};
(function() {
var result;
var adding = function(one, two) {
var one1 = document.forms["myForm"]["one"].value;
var two2 = document.forms["myForm"]["two"].value;
var one=parseFloat(one.replace(/\,/g,''));
var two=parseFloat(two.replace(/\,/g,''));
result = parseInt(one1) + parseInt(two2);
console.log(result);
var number = document.getElementById("number");
number.innerHTML = result;
console.log(one, two, result)
return result;
}
window.calculator.init = function() {
document.getElementById('add').addEventListener('click', adding);
};
})();
html:
<body>
<form name="myForm">
<h4>numner 1</h4>
<input type="text" name="one" id="one"></input>
<h4>number 2</h4>
<input type="text" name="two" id="two"></input>
<input type="button" id="add">
</form>
<p id="number"> </p>
<script type="text/javascript" src="public/adder.js"></script>
<script>
calculator.init()
</script>
</body>
</html>
test spec:
beforeEach(function() {
var fixture = '<div id="fixture"> <input type="text" name="one" id="one">' +
'<input type="text" name="two" id="two">' +
'<input type="button" id="add" >' +
'<p id="number"> </p></div>';
document.body.insertAdjacentHTML(
'afterbegin',
fixture);
});
// remove the html fixture from the DOM
afterEach(function() {
document.body.removeChild(document.getElementById('fixture'));
});
// call the init function of calculator to register DOM elements
beforeEach(function() {
window.calculator.init();
});
it('should return 3 for 1 + 2', function() {
var x = document.getElementById('one').value = 1;
var y = document.getElementById('two').value = 2;
document.getElementById('add').click();
expect(document.getElementById('number').innerHTML).toBe('3');
});
Here is a working example. Basically all I did was add <form name="myForm"> and </form> to the HTML in the fixture variable and it started working. You want to supply an element to your test that is essentially the same as the element you want to test in the DOM. You can leave out items that aren't important like the <h4> elements that you already did. Otherwise you need to include all the elements that will be required for the tests.
In this case you are looking for values in the form element:
var one1 = document.forms["myForm"]["one"].value;
var two2 = document.forms["myForm"]["two"].value;
var one=parseFloat(one1.replace(/\,/g,''));
var two=parseFloat(two2.replace(/\,/g,''));
But you weren't including the form in your test. You only had the two input elements, the button, and the element where the results are displayed. The following should get you on the right path.
beforeEach(function() {
var fixture = '<div id="fixture">' +
'<form name="myForm">' +
'<input type="text" name="one" id="one">' +
'<input type="text" name="two" id="two">' +
'<input type="button" id="add" >' +
'</form>' +
'<p id="number"> </p></div>';
document.body.insertAdjacentHTML(
'afterbegin',
fixture);
});
// remove the html fixture from the DOM
afterEach(function() {
document.body.removeChild(document.getElementById('fixture'));
});
// call the init function of calculator to register DOM elements
beforeEach(function() {
window.calculator.init();
});
it('should return 3 for 1 + 2', function() {
var x = document.getElementById('one').value = 1;
var y = document.getElementById('two').value = 2;
document.getElementById('add').click();
expect(document.getElementById('number').innerHTML).toBe('3');
});

JS function undefined when calling from certain click events in handlebars template

I am not understanding why the function goToProfile(otherUserId) is 'not defined' only some of the times.
For example, on the page, I have a link to a user that works fine by using the '.userProfileLink' click event.
<%= link_to image_tag(user.avatar.url(:medium)), "/profile/#{user.id}/view", class: "userProfileLink", :"value" => user.id, remote: true %>
Then I click #requestMeeting which renders this handlebars template:
<script id="request-meeting-form" type="text/x-handlebars-template">
<form id="requestMeetingForm">
<div class="form_section">
<h4 style="text-align:center;">Request 1 Hour Meeting</h4>
<br>
<div class="wrapper_input col_8_of_16">
<h4 class="label_standard">Date</h4>
<input type="text" id="meeting_date" class="input_standard datePicker" onfocus="this.blur()"></input>
<input type="hidden" id="alt_meeting_date" class="input_standard datePicker"></input>
</div>
<div class="wrapper_input col_4_of_16">
<h4 class="label_standard">Start Time</h4>
<input type="text" id="meeting_time" class="input_standard time_picker" onfocus="this.blur()"></input>
</div>
</div>
<div class="form_section">
<div class="wrapper_input">
<use xlink:href="#map"/></use></svg>
</div>
<br>
<div class="wrapper_input col_8_of_16">
<input type="text" name="location" id="locationField" placeholder="Location Name" class="input_standard" ></input>
</div>{{!--
--}}<div class="wrapper_input col_8_of_16">
<input type="text" name="location_address" id="addressField" placeholder="Location Address" class="input_standard"></input>
</div>
<input type="hidden" id="currentUser"></input>
</div>
<div id="mapLocation">
</div>
**************** IMPORTANT PART *********************
<div class="form_section submit_cancel">
<div class="wrapper_input cancel" >
<use xlink:href="#circleClose"/></svg>
</div>
********************************************
<div class="wrapper_input submit">
<div class="actions">
<button type="submit" class="btn_primary" id="requestMeetingButton" >Request Meeting <svg class="" ><use xlink:href="#sendPlane"/></svg></button>
</div>
</div>
</div>
</form>
</script>
When I try to call goToProfile again in the template above, I get an error that goToProfile is not defined.
application.js:
$(document).on('click', '#goToProfile', function(e) {
e.preventDefault();
var value = $(this).attr('value')
var otherUserId = parseInt(value);
$('#profileSection').empty();
goToProfile(otherUserId);
});
var ready;
ready = function(){
var currentUserId;
getCurrentUser().done(function() {
var currentUserId = currentUserId
});
$('.userProfileLink').click(function(e) {
var value = $(this).attr('value')
otherUserId = value;
goToProfile(otherUserId);
});
var profileSource = $("#user-profile").html();
var compiledProfile = Handlebars.compile(profileSource);
var languageSource = $("#languages").html();
var compiledLanguage = Handlebars.compile(languageSource);
var language = ""
var currentUserId;
var goToProfile = function(otherUserId) {
$.ajax({
url: '/get_user',
type: 'GET',
data: {otherUserId: otherUserId},
success: function(user) {
var profileInfo;
getUserImage(otherUserId).done(function() {
var profileInfo = {
first_name: user.first_name,
location: user.location,
bio: user.bio,
nationality: user.nationality,
userId: user.id,
userImage: userImage,
};
var profileTemplate = compiledProfile(profileInfo);
$('.yieldedInfo').empty();
$('.yieldedInfo').append('<div class="profileContainer">' + profileTemplate + '</div>');
});
getLanguagesUsers(user.id);
$('#requestMeeting').click(function(e) {
e.preventDefault();
requestMeetingForm(this.value);
});
},
error: function(err) {
console.log(err);
}
});
};
var getLanguagesUsers = function(userId) {
$.ajax({
url: '/user_languages',
type: 'GET',
data: {userId: userId},
success: function(languages) {
for(var i=0; i<languages.length; i++) {
if(languages[i].level != 5) {
var id = languages[i].language_id
var langUrl = '/languages/'+id;
$.getJSON(langUrl, function(lang) {
var language = lang.language
var languageInfo = {
language: language
};
var languageTemplate = compiledLanguage(languageInfo);
$('#learningLanguages').append(languageTemplate);
});
} else {
var id = languages[i].language_id;
var langUrl = '/languages/'+id;
$.getJSON(langUrl, function(lang) {
var language = lang.language
var languageInfo = {
language: language
};
var languageTemplate = compiledLanguage(languageInfo);
$('#fluentLanguages').append(languageTemplate);
});
};
};
},
error: function(err) {
console.log(err);
}
});
};
};
$(document).ready(ready);
$(document).on('page:load', ready);
How can I make goToProfile() available to be called all the time?
Thanks!
You can do what you need by binding the click event handler at the same scope level as the function it needs to call...
var ready = function(){
$(document).on('click', '#goToProfile', function(e) {
e.preventDefault();
var value = $(this).attr('value')
var otherUserId = parseInt(value);
$('#profileSection').empty();
goToProfile(otherUserId);
});
// the rest of your ready function goes here
};
If you do it that way then the event handler has access to the goToProfile function as they're both within the ready function. Nothing outside that function can access the private methods inside it.

Categories

Resources