I am trying to get data stored in attributes of dynamically created elements that have been added to the DOM.
When a button is clicked, an AJAX call is made which returns a collection of objects. Using Javascript/JQuery, I am then adding new HTML elements for each of these returned objects, and adding their property values to attributes on the element. I am then adding a click listener to each of these dynamically created elements. When clicked I want to get the value in these attributes.
At the moment the id value is present, but the value of name is undefined.
For example, given the following HTML:
<input type="button" id="button" value="Get objects" />
<div id="objects-wrapper"></div>
Json response from server:
[
{
"id": 16,
"name": "eeeee",
},
{
"id": 17,
"name": "MIT Top New"
}
]
$(document).ready(function() {
$('#button').click(function() {
var id = $(this).attr('id');
var posting = $.post('/get/objects', {
id: id
});
posting.done(function(data) {
var objectsWrapper = $('#objects-wrapper');
objectsWrapper.empty();
if (data.length == 0) {
$(objectsWrapper).html('No objects found...');
} else {
$(objectsWrapper).empty();
for (i = 0; i < data.length; i++) {
var object = $('<div class="object">' + data[i].name + '</div>').on('click', function() {
var objectId = $(this).attr('id'); // <-- is present
var name = $(this).attr('name'); // <-- undefined
// do something with name
});
objectsWrapper.append(object);
}
}
});
return false;
});
});
The name value is present and is being used as the anchor text. Which I have verified as the following markup:
MIT Top New
How do I correctly get at the attribute name of the dynamically created anchor element?
You can use .find() of jQuery to find for the elements with selector in the DOM and make it work
Here is an example with your data.
var data = [
{
"id": 16,
"name": "eeeee",
},
{
"id": 17,
"name": "MIT Top New"
}
];
data.forEach(e=>{
$("#objects-wrapper").append(` </br> ${e.name} </br>`)
});
$("#button").click(function(){
$("#objects-wrapper").find("a").each(function(){
console.log($(this).attr("name"))
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="button" id="button" value="Get objects" />
<div id="objects-wrapper"></div>
By the way in your code, why you need to get it from DOM ? you're assigning the name yourself why not use it ? data[i].name this is the name right. Use it instead of getting from the DOM again
Related
I want to retrieve a JSON object when the user clicks the html link. i want to retrieve it by it's ID and display everything in the object on the html page. I am also using session storage..... I want the user to be taken to the info.html page after they follow the html link.
my html code so far:
<div class="col">
<!-- team-img -->
<div class="team-block">
<div class="team-content">
<h4 class="text-white mb0">Chocolate Cake </h4>
<p class="team-meta">Large</p>
</div>
<div class="overlay">
<div class="text">
<h4 class="mb0 text-white"> Chocolate Cake </h4>
<p class="mb30 team-meta"> Large </p>
<p>Large Chocolate cake. 15 servings.</p>
<p>Further info</p>
</div>
</div>
</div>
</div>
The ID of the cake is "1" In the JSON file. I want all the details of the cake to be displayed when the user clicks the link. I want the user to be taken to info.html. The data of the cake which is stored in the JSON should be displayed there. The problem is with this line:
<p>Further info</p>
My JSON file is called cakes.json
below is my .js file
var ajax=function(url,success)
{
var ajaxRequest = new XMLHttpRequest();
var handleResponse=function()
{
if(ajaxRequest.readyState===4)
{
if(ajaxRequest.status===200)
{
var data=JSON.parse(ajaxRequest.responseText);
success(data); //this will call populateList
}
}
}
ajaxRequest.addEventListener("readystatechange",handleResponse,false);
ajaxRequest.open('GET', url, true);
ajaxRequest.send(null);
}
var navList;
var contentDiv;
function createHandler(car)
{
return function(){
sessionStorage.setItem("cake",JSON.stringify(cake));
}
}
function populateList(cakes)
{
navList=document.getElementById("nav");
contentDiv=document.getElementById("content");
cakes.forEach(function(cake){
var newLi=document.createElement("ul");
var newLink=document.createElement("a");
newLink.innerHTML=cake.name;
newLink.setAttribute("href","info.html");
newLink.addEventListener("click", createHandler(cake), false)
newLi.appendChild(newLink);
navList.appendChild(newLi);
})
}
function init(){
ajax("data/cakes.json",populateList);
}
init();
JSON file:
[
{
"id":1,
"cake":"chocolate cake",
"servings":"15",
"size":"10",
"code":"ed39"
},
]
Any Help would be greatly appreciated.
I've done an example of how this can be done using your structure of array containing multiple objects. Also I've modified your html added data-id parameter instead of id usually you don't save the id of an object in the id of html element(not best practice), you can use the data- params, there is also a function in jQuery that reads these parametes $(selector).data('identifier')
var json = [{
"id": 1,
"cake": "chocolate cake",
"servings": "15",
"size": "10",
"code": "ed39"
}, {
"id": 2,
"cake": "vanilla cake",
"servings": "15",
"size": "10",
"code": "ed39"
}];
$(document).on('click', '.cakeDetailsButton', function() {
var id = $(this).data('id'),
details = getDetailsById(id), //Here all the details for the cake
resultDiv = $('.result');
resultDiv.text('');
$.each(details, function(key, value) {
resultDiv.append(key + ' -- ' + value + '<br/>') // Here you can do whatever with the details
})
});
function getDetailsById(id) {
for (var i = 0; i < json.length; i++) {
if (json[i].id == id) {
return json[i];
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p><a class="cakeDetailsButton" href="#" data-id="1">Further info 1</a></p>
<p><a class="cakeDetailsButton" href="#" data-id="2">Further info 2</a></p>
<div class="result">
</div>
EDIT - Update
In order to add your json in the localStorage in order to access it from anywhere update the following
.js file
function populateList(cakes)
{
localStorage.setItem('cakesJson', cakes); //This adds an object to the localStorage with the key cakesJson and value the cakes object
navList=document.getElementById("nav");
contentDiv=document.getElementById("content");
cakes.forEach(function(cake){
var newLi=document.createElement("ul");
var newLink=document.createElement("a");
newLink.innerHTML=cake.name;
newLink.setAttribute("href","info.html");
newLink.addEventListener("click", createHandler(cake), false)
newLi.appendChild(newLink);
navList.appendChild(newLi);
})
}
Also then in the code provided by me above you should change the following
function getDetailsById(id) {
var json = localStorage.getItem("cakesJson"); // Here you retrieve the values stored in the localStorage
for (var i = 0; i < json.length; i++) {
if (json[i].id == id) {
return json[i];
}
}
}
The event listener remains the same as in the snippet
$(document).on('click', '.cakeDetailsButton', function() {
var id = $(this).data('id'),
details = getDetailsById(id), //Here all the details for the cake
resultDiv = $('.result');
resultDiv.text('');
$.each(details, function(key, value) {
resultDiv.append(key + ' -- ' + value + '<br/>') // Here you can do whatever with the details
})
});
I have a table categories and a documents. I want to create a new document and associate this document with a category already created.
The category table has the title field.
In the document creation form I want to put the categories already created in a select.
I tried doing this in the code below, but I ended up getting the select a key from the category -L0_xe_FIK9QdfTGhBDG for example, but I wanted the category title.
var documentosRef = firebase.database().ref('documentos');
var categoriasRef = firebase.database().ref('categorias');
var keyDocumento = ""
function initFirebase(){
categoriasRef.on('value', function(data) {
$('#categoria').html('');
for(categoria in data.val()){
option = "<option>"+categoria+"</option>"
$('#categoria').html($('#categoria').html()+option);
}
})
}
Structure:
{ "categorias": {
"L0_xe_FIK9QdfTGhBDG": {
"titulo": "Categorias 1"
},
"-L0a0FPFkXkKb3VNFN0c":{
"titulo": "Categorias 2"
}
}
Let check it out: JavaScript for/in Statement
var categorias = data.val();
for(var key in categorias){
option = "<option>"+categorias[key].titulo +"</option>"
$('#categoria').html($('#categoria').html()+option);
}
How could I create a search form that will search for the entered term inside a JSON file?
So if the search term is equal to a title inside the location object, it should return that object info. If there is no match, give the user feedback that there are no items found
I created a search input:
<form action="" method="get">
<input id="search" type="text" placeholder="Search term">
<input type="submit" class="button">
</form>
My JSON looks like this:
{
"title": "Locations",
"locations": [
{
"title": "New York",
"url": "api/newyork.js"
},{
"title": "Dubai",
"url": "api/dubai.js"
},{
"title": "Netherlands",
"url": "api/netherlands.js"
},{
"title": "Lanzarote",
"url": "api/lanzarote.js"
},{
"title": "Italy",
"url": "api/italy.js"
}
]
}
Update:
I came up with the following, using jQuery:
$("#search").change(function() {
var arrival = $(this).val();
$.getJSON( "api/videoData.js")
.done(function(data) {
// update your ui here
console.dir(data.pages);
var dataArr = data.pages;
// Iterate over each element in the array
for (var i = 0; i < dataArr.length; i++){
// look for the entry with a matching `code` value
if (dataArr[i].title == arrival){
// we found it
console.log(dataArr[i].title);
} else {
console.log('Houston, we have a problem');
}
}
}).fail(function(data) {
// handle error here
console.log('no results found');
});
});
This is working, only it should be entered exactly as stored in the JSON.
So when you search for "Italy" and you use lowercase type, it will not find the object. Also it will not give any entries when you search for example: ne. I would like to get Netherlands and New York as search results.
Here is a snippet that demonstrates how the lookup could be done. It only loads the JSON once. I have included the test data for when the JSON request fails, which it will in this demo. At every change of the input value a short list of matches is shown in a div below the input. The submit button is not included, as the search is immediate.
Try it.
// testData is defined for demo only. Can be removed
var testData = [
{
"title": "New York",
"url": "api/newyork.js"
},{
"title": "Dubai",
"url": "api/dubai.js"
},{
"title": "Netherlands",
"url": "api/netherlands.js"
},{
"title": "Lanzarote",
"url": "api/lanzarote.js"
},{
"title": "Italy",
"url": "api/italy.js"
}
];
// Variable to hold the locations
var dataArr = {};
// Load the locations once, on page-load.
$(function() {
$.getJSON( "api/videoData.js").done(function(data) {
window.dataArr = data.pages;
}).fail(function(data) {
console.log('no results found');
window.dataArr = testData; // remove this line in non-demo mode
});
});
// Respond to any input change, and show first few matches
$("#search").on('keypress keyup change input', function() {
var arrival = $(this).val().toLowerCase();
$('#matches').text(!arrival.length ? '' :
dataArr.filter(function(place) {
// look for the entry with a matching `code` value
return (place.title.toLowerCase().indexOf(arrival) !== -1);
}).map(function(place) {
// get titles of matches
return place.title;
}).join('\n')); // create one text with a line per matched title
});
// submit button is not needed really
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="search" type="text" placeholder="Search term">
<div id="matches" style="height:70px; overflow-y:hidden; white-space:pre"></div>
The solution has a few steps, let us know which step you can't do:
Call a JS function when the user clicks the button
Read the file from disk on the server into a JS variable in the browser
Use lodash.js to get the url from the JS variable for the search term
Display results to the user
But taking a stab at the simplest answer, the way I'd do it:
Load your JSON file with the page, like any Javascript file.
Load lodash.js.
Call your JSON file towns.js and make it look like this:
var cities =
{
"title": "Locations",
"locations":
[
{
"title": "New York",
"url": "api/newyork.js"
},
{
"title": "Dubai",
"url": "api/dubai.js"
}
]
}
And then your HTML is something like this:
<input type="" class="button" onclick='go()'>
<script src='towns.js' />
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js' />
<script>
function go()
{
var name = document.getElementById('search').value;
var result = _.find(cities.locations, {'title': name});
if (!result)
window.alert('Nothing found');
else
window.alert('Go to ' + result.url);
}
<script>
If you intend your json file as static and not very huge one then you better load it at once on page load event(preventing sending the same requests dozens of times). Try this approach:
var xhr = new XMLHttpRequest(),
locations = {};
xhr.overrideMimeType("application/json");
xhr.open('GET', 'locations.json', true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == "200") {
var content = JSON.parse(this.response),
locations_arr, i, count, title;
locations_arr = content['locations'];
for (i = 0, count = locations_arr.length; i < count; i++) {
title = locations_arr[i]['title'].toLowerCase();
locations[title] = locations_arr[i];
}
console.log(locations);
}
};
xhr.send(null);
Add some identifier to your form element (id="myForm") and 'name' attribute to your input field (name="search");
document.getElementById('myForm').onsubmit = function() {
var search_value = this.search.value.trim().toLowercase();
if (search_value && location[search_value]) {
console.log(location[search_value]);
} else {
alert("Object with specified title not found!");
}
// You must return false to prevent the default form behavior
return false;
}
As you said in your update with this code:
So when you search for "Italy" and you use lowercase type, it will not find the object. Also it will not give any entries when you search for example: ne. I would like to get Netherlands and New York as search results.
$("#search").change(function() {
var arrival = $(this).val();
$.getJSON( "api/videoData.js", { arrivalDate: arrival })
.done(function(data) {
// update your ui here
console.dir(data.pages);
var dataArr = data.pages;
// Iterate over each element in the array
for (var i = 0; i < dataArr.length; i++){
// look for the entry with a matching `code` value
if (dataArr[i].title == arrival){
// we found it
console.log(dataArr[i].title);
} else {
console.log('Houston, we have a problem');
}
}
}).fail(function(data) {
// handle error here
console.log('no results found');
});
});
Replace this line:
if (dataArr[i].title == arrival){
for
if (dataArr[i].title.toLowerCase().contains(arrival.toLowerCase())){
And now it will match all the string that contains the string that you are searching...
I would like to get the row id of selected item in my autocomplete function, I get the values of my source from a php variable.
<script>
$(function() {
var availableTags = [ <? php echo($toto); ?> ];
$("#foo").autocomplete({
source: availableTags
});
});
</script>
I already tried this function but it does not seem to work. In fact, when I add it to my script, my autocomplete won't work anymore.
<script>
$(function () {
var availableTags = [ <? php echo($ListeNomsFormateeFinale); ?> ];
$("#nomClient").autocomplete({
source: availableTags
select: function (event, ui) {
$("#textfield1").val(ui.item.label); // display the selected text
$("#textfield2").val(ui.item.value); // display selected id
return false;
}
});
});
</script>
What am I doing wrong here? and is there a quick fix to this problem?
Edit:
I actualy needed to add a comma after source: availableTags, I also deleted the return false. but it dosen't return the id of the selected row, it actually writes the same value in the two textfields textfield1 and textfield2
From : Api Jquery UI - Autocomplete - option source
Array: An array can be used for local data. There are two supported formats:
An array of strings: [ "Choice1", "Choice2" ]
An array of objects with label and value properties: [ { label: "Choice1", value: "value1" }, ... ]
The label property is displayed in the suggestion menu. The value will be inserted into the input element when a user selects an item. If just one property is specified, it will be used for both, e.g., if you provide only value properties, the value will also be used as the label.
The second point (2.) give a way to store the "id" (or something else) of the selected object. By example :
var yourSource = [ { label: "Choice1", id: "id1" } ];
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<form>
<input type="text" id="fooInput" />
</form>
<div id="result">
</div>
<script type="text/javascript">
var yourSource = [
{
label: "A",
id: "id1"
},
{
label: "B",
id: "id2"
}];
$("#fooInput").autocomplete({
source: yourSource,
select: function(event, ui) {
var e = ui.item;
var result = "<p>label : " + e.label + " - id : " + e.id + "</p>";
$("#result").append(result);
}
});
</script>
So try to format your data source like this :
var source = [ {label:"Foo", id:"1"}, ... ];
I have the following JSON:
var questions = {
section: {
"1": question: {
"1": {
"id" : "1a",
"title": "This is question1a"
},
"2": {
"id" : "1b",
"title": "This is question2a"
}
},
"2": question: {
"1": {
"id" : "2a",
"title": "This is question1a"
},
"2": {
"id" : "2b",
"title": "This is question2a"
}
}
}
};
NOTE: JSON changed based on the answers below to support the question better as the original JSON was badly formatted and how it works with the for loop below.
The full JSON will have 8 sections and each section will contain 15 questions.
The idea is that the JS code will read what section to pull out and then one by one pull out the questions from the list. On first load it will pull out the first question and then when the user clicks on of the buttons either option A or B it will then load in the next question until all questions have been pulled and then do a callback.
When the button in the appended list item is clicked it will then add it to the list below called responses with the answer the user gave as a span tag.
This is what I have so far:
function loadQuestion( $section ) {
$.getJSON('questions.json', function (data) {
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item === $section) {
$('#questions').append('<li id="' + item.section.questions.question.id + '">' + item.section.questions.question.title + ' <button class="btn" data-response="a">A</button><button class="btn" data-response="b">B</button></li>');
}
}
});
}
function addResponse( $id, $title, $response ) {
$('#responses').append('<li id="'+$id+'">'+$title+' <span>'+$response+'</span></li>');
}
$(document).ready(function() {
// should load the first question from the passed section
loadQuestion( $('.section').data('section') );
// add the response to the list and then load in the next question
$('button.btn').live('click', function() {
$id = $(this).parents('li').attr('id');
$title = $(this).parents('li').html();
$response = $(this).data('response');
addResponse( $id, $title, $response );
loadQuestion ( $('.section').data('section') );
});
});
and the HTML for the page (each page is separate HTML page):
<div class="section" data-section="1">
<ul id="questions"></ul>
<ul id="responses"></ul>
</div>
I've become stuck and confused by how to get only the first question from a section and then load in each question consecutively for that section until all have been called and then do a callback to show the section has been completed.
Thanks
Do not have multiple id's in html called "section."
Do not have multiple keys in your JSON on the same level called "section". Keys in JSON on the same level should be unique just as if you are thinking about a key-value hash system. Then you'll actually be able to find the keys. Duplicate JSON keys on the same level is not valid.
One solution can be section1, section2, etc. instead of just section. Don't rely on data-section attribute in your HTML - it's still not good if you have "section" as the duplicate html id's and as duplicate JSON keys.
If you have only one section id in HTML DOM, then in your JSON you must also have just one thing called "section" e.g.:
var whatever = {
"section" : {
"1": {
"question" : {
"1" : {
"id" : "1a",
"title" : "question1a"
},
"2" : {
"id" : "2a",
"title" : "question2a"
}
}
},
"2": {
"question" : {
"1" : {
"id" : "1a",
"title" : "aquestion1a"
},
"2" : {
"id" : "2a",
"title" : "aquestion2a"
}
}
}
}
}
console.log(whatever.section[1].question[1].title); //"question1a"
To get question, do something like this:
function loadQuestions(mySectionNum) {
$.getJSON('whatever.json', function(data){
var layeriwant = data.section[mySectionNum].question;
$.each(layeriwant, function(question, qMeta) {
var desired = '<div id="question-' +
qMeta.id +
'"' +
'>' +
'</div>';
$("#section").append(desired);
var quest = $("#question-" + qMeta.id);
quest.append('<div class="title">' + qMeta.title + '</div>');
//and so on for question content, answer choices, etc.
});
});
}
then something like this to actually get the questions:
function newQuestion(){
var myHTMLSecNum = $("#section").attr('data-section');
loadQuestions(myHTMLSecNum);
}
newQuestion();
//below is an example, to remove and then append new question:
$('#whatevernextbutton').on('click',function(){
var tmp = parseInt($("#section").attr('data-section'));
tmp++;
$("#section").attr('data-section', tmp);
$("#section").find('*').remove();
newQuestion();
});
Technically your getJSON function always retrieves the same data. Your code never compares the id given to the id you're extracting.
Your getJSON should look something like:
function loadQuestion( $section ) {
for (var i = 0; i < questions.section.length; i++) {
var item = questions.section[i];
if (item.id === $section) {
for (var j = 0; j < item.questions.length; j++) {
$('#questions').append('<li id="' +
item.questions[i].id + '">' +
item.questions[i].title +
' <button class="btn" data-response="a">A</button><button class="btn" data-response="b">B</button></li>'
);
}
}
}
}
Modify your JSON to:
var questions = {
section: [{
id: 1,
questions: [{
id: "1a",
title: "This is question1a"
},{
id: "2a",
title: "This is question2a"
}]},{
id: 2,
questions: [{
id: "1a",
title: "This is question1a"
},{
id: "2a"
title: "This is question2a"
}]
}]
};
Edit: your first parameter of getJSON is the URL of the JSON returning service.
You don't need getJSON at all if your JSON is already defined on the client. I have modified the code above.