I'm implementing autocomplete using webSocket. When I type in the input field which has the classname item-search-results, a bunch of result will show up search results screenshot. My problem is the result will is only attach to the very first item-search-results input field.
But I need the results show up under the right item-search-results input field.
For example, I type on the 4th item-search-results input field, but the results are attach to the first one results are attach to the first row screenshot
Here is my webSocket js, I use jQuery:
$(function () {
let webSocket = new WebSocket("ws://localhost:8000/autocomplete");
webSocket.onopen = (msgEvent) => {
console.log('connected to WebSocket!');
};
webSocket.onmessage = (msgEvent) => {
/* results shows {"results":{"results":[{..}]}}.
results.results shows {results:[{..}]}
results.results.results shows [{...}], which is an array */
let results = JSON.parse(msgEvent.data),
resultsArr = results.results.results;
console.log(resultsArr);
$.each(resultsArr, (index, value) => {
$('<div>' + value['name'] + '</div>').attr('id', 'item-search-results-' + index).appendTo($('.item-search-results'));
});
};
webSocket.onclose = (msgEvent) => {
console.log('disconnected');
};
webSocket.onerror = (msgEvent) => {
console.log('there\'s an error');
};
/**
* Request to display data
*/
$('.add-items-table').on('input', '.item-input', (e) => {
let value = e.target.value;
webSocket.send(value);
console.log(value);
})
})
Websockets are irrelevant here, and I don't understand why you are doing an append inside loop. When trying to do something like this, you need to use the $(this) selector which will be the element you actually click.
At the top of your script create a global variable or namespace.
var Item = {};
/* In this chunk of code, create an object which you can use as a reference */
$('.add-items-table').on('input', '.item-input', (e) => {
/* this will be the correct .item-search-results div */
var Item.list = $(this).siblings('.item-search-results');
let value = e.target.value;
webSocket.send(value);
console.log(value);
})
Finally, append to the correct <div>.
.appendTo(Item.list);
Not sure about Websocket But here is how you will approach.Get last Row of table and append data after that particular row.
var placeHolder=` <tr>
<td style="width: 16.66%">
<input type="text" name="quanty" value="">
</td>
<td class="item-search-container">
<input class="item-input" id="item-input-0" type="search" name="item" value="">
<div class="item-search-results"></div>
</td>
<td>
<input type="text" name="quanty" value="">
</td>
</tr>`;
function addItem(){
let totalElem=document.getElementsByClassName('tr').length;
let lastElem=document.getElementsByClassName('tr')[totalElem-1];
$.get( "https://jsonplaceholder.typicode.com/posts/1", function( data ) {
$.each(data, function(i, item) {
$(lastElem).after(placeHolder);
});
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="item-form">
<table class="add-items-table table table-hover ">
<thead>
<tr>
<th>Quanty</th>
<th>Item</th>
<th>Comment</th>
<th>Remove</th>
</tr>
</thead>
<tbody class="item-row">
<tr class="tr">
<td style="width: 16.66%">
<input type="text" name="quanty" value="">
</td>
<td class="item-search-container">
<input class="item-input" id="item-input-0" type="search" name="item" value="">
<div class="item-search-results"></div>
</td>
<td>
<input type="text" name="quanty" value="">
</td>
<td>
<button class="remove-item-button btn-block btn-outline-danger" type="reset" name="remove">
<i class="fa fa-trash-o" aria-hidden="true"></i>
</button>
</td>
</tr>
</tbody>
</table>
<button class="add-item" onClick="addItem()">Add Another Item</button>
</section>
The problem here is that you are appending it to $('.item-search-results') that is a class and is returned as an array. When you run .appendTo($('.item-search-results')) it will append to the first item of the array.
You should use a more specific Id for each roll and append by Id.
I think #manikant 's idea of creating a template is great, but I would introduce a variable that you can change for each new row you create and give a different Id to each .item-search-results div. But you would have to send this to the websocket and receive it back to call the right Id to append.
Related
I'm trying to insert HTML data dynamically to a table that is dynamically created, but when I try to attach an addEventListner for the button that is dynamically created the event is not firing. The solution would be appreciated.
const put = document.querySelector(".puthere");
const v1 = document.querySelector(".v1");
const v2 = document.querySelector(".v2");
const create = document.querySelector(".create");
const updateDelete = document.querySelector(".update-delete");
const update = document.querySelectorAll(".active-update");
const dynamic = document.querySelector(".dynamic");
//FUNCTIONS
const operations = function (v1, v2) {
const html = ` <tr class = "update-delete">
<td> <input type="${v1}"></td>
<td ><input type="${v2}"></td>
<td> <button class = "active-update" data-set=".active-update"> UPDATE</button></td>
<td> <button > ❌ </button></td>
</tr>`;
put.insertAdjacentHTML("beforeend", html);
};
//CREATE TABLE COLUMNS
create.addEventListener("click", function (e) {
operations(v1.value, v2.value);
});
//Ataching eventlistner to parent element
updateDelete.addEventListener("click", function (e) {
if(e.target.classList.contains('active-update'){
console.log('click)})
});
<div >
<table class = "puthere">
<tr class="dynamic">
<th>BOOKS</th>
<th class = "books">PRICE</th>
<th > <button class="create" > CREATE</button> </th>
</tr>
<tr class = "update-delete dynamic">
<td><input type="text" class="v1"></td>
<td><input type="text" class="v2"></td>
<td> <button class = "active-update" data-set=".active-update"> UPDATE </button></td>
<td> <button > ❌ </button></td>
</tr>
</table>
</div>
You should notice that you get updateDelete before you create another dynamic part. You could log updateDelete and you will find that it nerver changed.
So you could bind a click listener to higher level element, like this:
put.addEventListener('click', function (e) {
if (e.target.classList.contains('active-update')) {
console.log('click')
}
})
Or add click listener to every button you created dynamically.
I am using multiple text box to insert data into database table. So doing few researches and used online resources to make it work. But stuck into one basic thing, I guess. The issue is with the jQuery mapping. Let me share the code here:
//Add row to the table
$('#btnAddRow').on('click', function() {
var $clone = $('#tblQuesAns tbody tr:last').clone();
$clone.find('input').val('')
$('#tblQuesAns tbody').append($clone);
});
//Add more rows for option
$('body').on('click', '.addOptions', function() {
$(this).parent().append('<div><input class="txtOptions" type="text" /></div>');
});
//Get text box values
$('#btnGetValues').on('click', function() {
const allData = $('#tblQuesAns tbody tr').map(function() {
const $row = $(this),
question = $row.find('.txtQuestion').val(),
options = $row.find('.txtOptions').map(function() {
return this.value;
}).get().join(" ");
//return { question, options };
alert(question + ' ' + options.replace(/\s+/g, "_"));
}).get();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<button id="btnAddRow" type="button">
Add Row
</button>
<button id="btnGetValues" type="button">
Get Values
</button>
<table id="tblQuesAns" border="1">
<thead>
<tr>
<th>Question</th>
<th>Options</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input class="txtQuestion" value="Capital of Englnad" />
</td>
<td>
<input class="txtOptions" value="London" />
<span class="addOptions">(+)</span>
</td>
</tr>
<tr>
<td>
<input class="txtQuestion" value="Current Pandemic" />
</td>
<td>
<input class="txtOptions" value="Corona" />
<span class="addOptions">(+)</span>
</td>
</tr>
</tbody>
</table>
By default, jQuery map uses comma and I tried to remove those by using replace method as follows:
options.join(' ').replace(/\s+/g, "_")
Now I may have options that may contain comma. For example:
Question Options
Question 1 New York
Jakarta
London, Paris
Munich
So problem is, the values having space from text boxes also get replaced with the underscore sign replace(/\s+/g, "_"). So I get this output:
New_York_Jakarta_London,_Paris_Munich
But my expected output is this:
New York_Jakarta_London, Paris_Munich
I tried a different way that works but in this case all the text box values get concatenated:
var options = $("input[name*='txtOptions']");
var str = "";
$.each(options, function(i, item) {
str += $(item).val();
});
The problem with the above is, when I've different questions say question 1, question 2, it'll merge all the options to both of them. Though I want specific options for both questions.
Something like this?
//Add row to the table
$('#btnAddRow').on('click', function() {
var $clone = $('#tblQuesAns tbody tr:last').clone();
$clone.find('input').val('')
$('#tblQuesAns tbody').append($clone);
});
//Add more rows for option
$('body').on('click', '.addOptions', function() {
$(this).parent().append('<div><input class="txtOptions" type="text" /></div>');
});
//Get text box values
$('#btnGetValues').on('click', function() {
const allData = $('#tblQuesAns tbody tr').map(function() {
const $row = $(this),
question = $row.find('.txtQuestion').val(),
options = $row.find('.txtOptions').map(function() {
return this.value;
}).get().join("_");
return {question,options}
}).get()
const x = allData.map(item => `${item.question}_${item.options}`).join(" ")
console.log(x)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<button id="btnAddRow" type="button">
Add Row
</button>
<button id="btnGetValues" type="button">
Get Values
</button>
<table id="tblQuesAns" border="1">
<thead>
<tr>
<th>Question</th>
<th>Options</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input class="txtQuestion" value="Capital of England" />
</td>
<td>
<input class="txtOptions" value="London" />
<span class="addOptions">(+)</span>
</td>
</tr>
<tr>
<td>
<input class="txtQuestion" value="Current Pandemic" />
</td>
<td>
<input class="txtOptions" value="Corona" />
<span class="addOptions">(+)</span>
</td>
</tr>
</tbody>
</table>
I have a html table created using jQuery:
success: function(data, textStatus, errorThrown) {
var rows ="";
function formatItem(data) {
return '<td>'+data.name + '</td> <td> ' + data.price + ' </td><td>' + "<input></input>" +'</td>';
}
$.each(data, function (key, item) {
$('<tr>', { html: formatItem(item) }).appendTo($("#foodnames"));
});
}
This is what the interface looks like:
The table is working fine with all the data showing.
The problem is finding the sum of the third column. Where I can enter a number and display it using an id.
Is there anyway to do it?
What you want to do is to use jQuery to select the table, and all of the third td's for each row, then sum it. The basic pseudocode is:
Clear the output box.
ForEach TR
Select the third TD
Add that value to the output box.
End ForEach
To do that in jQuery, you just need to know how to select the right values. Assigning relevant class/id names is helpful.
I put together a basic example that you can run. It will tabulate the total of the third column dynamically, as you change the value. I hard coded the price column, but you could easily put some other values or input there.
I put it in an onChange event handler, but if you are loading the data from a server or something, you could do document onLoad or whenever your ajax is complete.
//trigger an event when the input receives a change
$("#exampleTableContainer table td input").off("change").on("change", function(ele) {
//clear the out put box
$("#totalOut").val("0");
//for the table container, select all tr's within the table's tbody.
//Excluding tbody will also select the thead.
$("#exampleTableContainer table tbody tr").each(function(index, rowElement) {
//tablulate the cost of the current row
var rowCost = parseInt($(rowElement).find(".cost").text()) * parseInt($(rowElement).find(".amount input").val());
//if the rowCost is a valid number, add it to whatever is in the output box
if (rowCost) $("#totalOut").val(parseInt($("#totalOut").val()) + rowCost)
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="exampleTableContainer">
<table>
<thead>
<tr>
<th class="item">Item</th>
<th class="cost">Cost</th>
<th class="amount">Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td class="item">Item 1</td>
<td class="cost">123</td>
<td class="amount">
<input type="number">
</td>
</tr>
<tr>
<td class="item">Item 2</td>
<td class="cost">1</td>
<td class="amount">
<input type="number">
</td>
</tr>
<tr>
<td class="item">Item 3</td>
<td class="cost">2</td>
<td class="amount">
<input type="number">
</td>
</tr>
<tr>
<td class="item">Item 4</td>
<td class="cost">4</td>
<td class="amount">
<input type="number">
</td>
</tr>
</tbody>
</table>
<br>
<div>
Total:
<input id="totalOut" readonly value="0">
</div>
</div>
I'm not sure if you plan to use this in a production environment or not, so maybe this is overkill for what you're trying to accomplish, but I would recommend using an underlying data model bound to the table. Then you can get your sum from your data:
const data = [
{food: "Veggie burger", price: 200, qty:1},
// ...Add as many food items as you like
]
You would be able to use the data to build your table:
// Get a reference to the table and create a document fragment
const table = document.getElementById("table-body");
const body = document.createDocumentFragment();
// Fill the fragment with your data:
data.map((value, key) => {
// Row-building logic goes here
// this probably isn't what you actually do here:
const row = document.createElement("tr");
row.className = key;
for (let x in value) {
const dataCell = document.createElement("td");
dataCell.className = x;
dataCell.innerHTML = value[x];
row.appendChild(dataCell);
}
body.appendChild(row);
});
table.innerHTML = "";
table.appendChild(body);
Then you can calculate your sum based on the data, not the UI:
const subTotal = data
.map((value) => value.price * value.qty)
.reduce((a, b) => a + b);
document.getElementById("total").textContent = subTotal;
You would set an event listener on the table(parent node) and use event.target to find the row and column (.qty in this case) and update the corresponding field (qty) in the data object when the input is changed.
$("#my-table").on("input", (e) => {
// You would probably be better off using a custom attribute than a class since there can be multiple classes, but we'll use class to keep it simple:
const column = $(e.target).parent("td").attr("class");
const row = $(e.target).parent("td").parent('tr').attr("class");
data[row][column] = e.target.value;
console.log(data);
});
This pattern also makes it easy to send the updated data back to the REST API to update your database later.
https://jsfiddle.net/79et1gkc/
I know you said you're using jQuery, but ES6 is much nicer in my opinion.
Try this:
$(document).ready(function(){
var total = 0;
$("#submit").click(function(){
$(".user_input").each(function(){
var value = parseInt($(this).val());
total += value;
});
$("#output").text(total);
});
});
HTML
<input type="text" name="value1" class="user_input"/>
<input type="text" name="value2" class="user_input"/>
<input type="text" name="value3" class="user_input"/>
<button name="submit" id="submit" value="calculate">
Calculate
</button>
<div>
<span>Total:</span><div id="output">
</div>
I have a restaurant_form which allows user to input menu items. Each menu item represent a table row which is added dynamically. Each table row has input for: menu item, price, halal(Boolean), and notes.
Here is a sample entry. data-ids and names of input elements are incremented.
<tbody class="menu-entry ">
<tr id='menu0' data-id="0" class="hidden">
<td data-name="name" class="name">
<input type="text" name='name0' placeholder='Menu Item' class="form-control"/>
</td>
<td data-name="price">
<input type="text" name='price0' placeholder='0.00' class="form-control"/>
</td>
<td data-name="halal">
<input type="checkbox" name="veg0" value="halal" class="form-control">
</td>
<td data-name="notes">
<textarea name="notes0" placeholder="Contains soy." class="form-control"></textarea>
</td>
<td data-name="del">
<button name="del0" class='btn btn-danger glyphicon glyphicon-remove row-remove'></button>
</td>
</tr>
</tbody>
What is the best way to retrieve data from the table? I have tried this:
$('#restaurant_form').submit(function () {
$('.menu-entry').each(function()
{
$(this).find('td').each(function(){
$(this).find("input").each(function() {
alert(this.value)
});
$(this).find("textarea").each(function() {
alert(this.value)
});
})
})
})
The alert() shows the correct values however I am wondering if there is a better way to do this?
Edit I simplified it using:
$('.menu-entry .form-control').each()
Also, after retrieving the values, how can I pass it to the view with a POST request? I would like to save the values to model
RestaurantMenu with columns name, price, halal and notes.
Thank you.
Here's what I did:
For every menu entry, I converted the values to a string separated by comma and added a hidden input to hold the value. I added class 'menu-row' to tr.
$('#restaurant_form').submit(function () {
$('.menu-row').each(function(){
var menu_entry = ""
$(this).find('.form-control').each(function(){
menu_entry = menu_entry + this.value + ","
})
$('#restaurant_form').append('<input type="hidden" name="menu_entries" value="'+ menu_entry +'" />')
alert(menu_entry)
})
})
In views.py :
menu_entries = request.POST.getlist('menu_entries')
for menu_entry in menu_entries:
entry = menu_entry.split(",")
if entry[1]:
price = round(float(entry[1]), 2)
else:
price = 0.00
if not entry[2]:
entry[2] = False
MenuItems.objects.create(name=entry[0], price=price, halal=entry[2], notes=entry[3], restaurant_id=r.id)
If anyone knows a better approach, I would love to know. Thank you!
I have buttons in a table which are created dynamically. I want to iterate through a table, get the tablerows which contain a checked checkbox and get the value of a button inside the tablerow. I want to push the values in an array after. The buttons don't have a unique ID so I cannot get their values by id.
I tried to get the values through giving the buttons a class and itering works fine but the array is filled with empty entries.
$("#bt_multiple_deletion").off().on("click", function () {
var files = [];
var rows = $(".select").find("input[type=checkbox]:checked");
rows.each(function () {
files.push($(this).find(".filefolder-button").text());
});
})
I really don't know what Im doing wrong. I tried to get the values with .text(), .val() etc.
My table row looks like this:
<tr class="select">
<td>
<span class="countEntries"><input id="lv_fifo_ctrl7_cb_delete_file" type="checkbox" name="lv_fifo$ctrl7$cb_delete_file" /></span>
</td>
<td>
<img src="images/icons/013_document_02_rgb.png" alt="document" />
</td>
<td class="name">//the button i want to get the value from
<input type="submit" name="lv_fifo$ctrl7$bt_file" value="013_document_png.zip" id="lv_fifo_ctrl7_bt_file" class="filefolder-button download file del" style="vertical-align: central" />
</td>
<td>
<span id="lv_fifo_ctrl7_lb_length">33.14 KB</span>
</td>
<td>
<span id="lv_fifo_ctrl7_lb_CreationTime">21.10.2014 07:34:46</span>
</td>
<td></td>
<td>
<input type="submit" name="lv_fifo$ctrl7$bt_del_file" value="delete" id="lv_fifo_ctrl7_bt_del_file" class="delete-button delete-file" />
</td>
</tr>
The problem is rows is the input elements not the tr elements so in the loop you need to find the tr which contains the input then find the target element inside it
$("#bt_multiple_deletion").off().on("click", function () {
var checked = $(".select").find("input[type=checkbox]:checked");
var files = checked.map(function () {
return $(this).closest('tr').find(".filefolder-button").val();
}).get();
})
Another option is
$("#bt_multiple_deletion").off().on("click", function () {
var rows = $(".select").find("tr").has('input[type=checkbox]:checked');
//var rows = $(".select").find('input[type=checkbox]:checked').closest('tr');
var files = rows.map(function () {
return $(this).find(".filefolder-button").val();
}).get();
})
#Timo Jokinen Do you need this
$("#bt_multiple_deletion").on("click", function () {
var files = [];
var rows = $(".select").find("input[type=checkbox]:checked");
rows.each(function () {
files.push($(this).parents("tr").find("td.filefolder-button").text());
});
console.log(files);
})
<table class="select">
<tr>
<td class="filefolder-button">test1</td>
<td><input type="checkbox" /></td>
</tr>
<tr>
<td class="filefolder-button">test2</td>
<td><input type="checkbox" /></td>
</tr>
<tr>
<td class="filefolder-button">test3</td>
<td><input type="checkbox" /></td>
</tr>
</table>
<button id="bt_multiple_deletion">delete</button>
Checkout example link here