jquery selecting child elements - javascript

The setup.
I am using MVC 5, and I have created a view with data sent in the form of a viewmodel.
With in this view I have rendered a List object as stacked div's, as seen below.
As you will see, I am displaying hidden fields, so that the viewModel send back the data to the controller on submit.
<div class="row item-row">
<div class="small-4 columns">
objType
</div>
<div class="small-6 columns">
<input id="object_0__Id" name="object[0].Id" type="hidden" value="999999">
<input id="object_0__Reference" name="object[0].Reference" type="hidden" value="myRef">myRef
<input id="object_0__RecordChanged" name="object[0].RecordChanged" type="hidden" value="NoChange">
</div>
<div class="small-2 columns remove-item">
<button class="button tiny expand centre button-gray" onclick="javascript: RemoveItem(999999);">Remove</button>
</div>
</div>
<div class="row item-row">
<div class="small-4 columns">
objType
</div>
<div class="small-6 columns">
<input id="object_1__Id" name="object[1].Id" type="hidden" value="000001">
<input id="object_1__Reference" name="object[1].Reference" type="hidden" value="myRef">myRef
<input id="object_1__RecordChanged" name="object[1].RecordChanged" type="hidden" value="NoChange">
</div>
<div class="small-2 columns remove-item">
<button class="button tiny expand centre button-gray" onclick="javascript: RemoveItem(000001);">Remove</button>
</div>
</div>
Ok, so the javascript function RemoveItem is:
function RemoveItem(id)
{
event.preventDefault();
var element = $(event.target).closest('.item-row');
$(element).closest('DeedReference_0__RecordChanged').val('Deleted'); ***** This is what I am trying to do.
$(element).hide();
}
From the above, when I click on say RemoveItem(00001), the variable element contains the following:
<div class="small-4 columns">
objType
</div>
<div class="small-6 columns">
<input id="object_0__Id" name="object[0].Id" type="hidden" value="000001">
<input id="object_0__Reference" name="object[0].Reference" type="hidden" value="myRef">myRef
<input id="object_0__RecordChanged" name="object[0].RecordChanged" type="hidden" value="NoChange">
</div>
<div class="small-2 columns remove-item">
<button class="button tiny expand centre button-gray" onclick="javascript: RemoveItem(000001);">Remove</button>
</div>
The value I need to update is object[0].RecordChanged, but at this moment in time, I do not know the index value. So I was planning on using the ends with selector, but am not able to get it to work.
I have got as far as:
$(event.target).closest('.item-row').children()[1]
But this gives me the div, since I have tried:
$(event.target).closest('.item-row').children()[1].Find('Id*"__RecordChanged"')
$(event.target).closest('.item-row [id*="RecordChanged"]')
$(event.target).closest('.item-row:[id*="RecordChanged"])
And using the variable
$(element [id*="RecordChanged"])
$(element [id$="RecordChanged"])
UPDATE
Fixed bug in code that was suggesting that I was looking at the wrong index.
Also, If I click the remove button for RemoveItem(000001), I am trying to update the value object_0__RecordChanged.

Changed view model to have an index property. Then changed placed the HTML.EditorFor within a foreach loop enabling me to populate the index property before it is rendered out.
Then the code was changed from:
function RemoveItem(id)
{
event.preventDefault();
var element = $(event.target).closest('.item-row');
$(element).closest('DeedReference_0__RecordChanged').val('Deleted'); ***** This is what I am trying to do.
$(element).hide();
}
to:
function RemoveItem(id)
{
event.preventDefault();
var recordChanged = '#object_' + id + '__RecordChanged';
$(recordChanged).val('Deleted');
var element = $(event.target).closest('.item-row');
$(element).hide();
}
Much simpler!

Related

How can I set some values using currentTarget with jQuery from different HTML elements?

Can anyone give me a hand with this?
I am trying to obtain different values depending which button is clicked and assign it into a variable.
A friend told me to add the values in an input to later by extracted by e.currentTarget but I was unable to make it work.
HTML:
<div class="curso-contenedor">
<div class="curso">
<input id="precio" value='12000' hidden>
<input id="cursoNombre" value='Web Developer' hidden>
<form><button class="btn-curso web-developer" id="webDeveloper">Agregar</button></form>
</div>
<div class="curso">
<input id="precio" value='13000' hidden>
<input id="cursoNombre" value='Marketing Digital' hidden>
<form><button class="btn-curso marketing-Digital" id="marketinDigital">Agregar</button></form>
</div>
</div>
jQuery:
$('.btn-curso').click(function(e){
let curso = {'precio': e.currentTarget('#precio'), 'curso': e.currentTarget('#cursoNombre')};
localStorage.setItem('datosCurso', JSON.stringify(curso));
e.preventDefault()
});
If anyone knows how to do this it would mean the world if you can help me since I have been trapped with this for days now trying different things.
Try this:
HTML
<div class="curso-contenedor">
<div class="curso">
<input name="precio" value='12000' hidden>
<input name="cursoNombre" value='Web Developer' hidden>
<button class="btn-curso web-developer" id="webDeveloper">Agregar</button>
</div>
<div class="curso">
<input name="precio" value='13000' hidden>
<input name="cursoNombre" value='Marketing Digital' hidden>
<button class="btn-curso marketing-Digital" id="marketinDigital">Agregar</button>
</div>
</div>
JQuery:
$('.curso-contenedor').on('click', '.curso', function(e){
let curso = {
'precio': $(e.currentTarget).find('input[name=precio]').val(),
'curso': $(e.currentTarget).find('input[name=cursoNombre]').val()
};
localStorage.setItem('datosCurso', JSON.stringify(curso));
e.preventDefault()
});
You should add delegate event listener to parent element
For more information: https://api.jquery.com/on/

How to use HTML template tag with jQuery?

Something strange bug is going on in my code. I want to use HTML template tag with jQuery, because all the rest of my code is jQuery, but I only found JavaScript examples with it. I tried to "translate" from JavaScript to jQuery, this is what I came up with.
$.getJSON( "../Controller/ControllerBookstore.php?show_books=true", function( data ) {
$.each( data, function( index, value ) {
// let clone = document.getElementById('table-template').content.cloneNode(true);
// clone.querySelector('#id').innerText = value.id;
// clone.querySelector('#author').innerText = value.author;
// clone.querySelector('#title').innerText = value.title;
// clone.querySelector('#isbn').innerText = value.isbn;
let clone = $("#table-template").clone(true);
$("#id",clone).text(value.id);
$("#author",clone).text(value.author);
$("#title",clone).text(value.title);
$("#isbn",clone).text(value.isbn);
//$(".container").append(clone);
$("#header").append(clone);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div id="myAlert" class="alert alert-success collapse">
<span id="alert-text"></span>
<a id="alert-close" class="close" href="#" aria-label="Close">×</a>
</div>
<div class="row" id="header">
<div class="col"><h5>ID</h5></div>
<div class="col"><h5>Author</h5></div>
<div class="col"><h5>Title</h5></div>
<div class="col"><h5>ISBN</h5></div>
<div class="col"><h5>Action</h5></div>
</div>
<template id="table-template">
<div class="row">
<div class="col" id="id"></div>
<div class="col" id="author"></div>
<div class="col" id="title"></div>
<div class="col" id="isbn"></div>
<div class="col buttons">
<button class='btn btn-info edit'>Edit</button>
<button class='btn btn-danger delete'>Delete</button>
</div>
</div>
</template>
<div class="row justify-content-center" >
<form action="" class="col-4">
<input id = "id-box" type="hidden" name="id">
<div class="form-group row">
<label class="col-4">Author</label>
<input id = "author-box" type="text" class="form-control col-8" name="author" placeholder="Enter the author of the book">
</div>
<div class="form-group row">
<label class="col-4">Title</label>
<input id = "title-box" type="text" class="form-control col-8" name="title" placeholder="Enter the title of the book">
</div>
<div class="form-group row">
<label class="col-4">ISBN</label>
<input id = "isbn-box" type="text" class="form-control col-8" name="isbn" placeholder="Enter the ISBN of the book">
</div>
<div class="form-group row">
<button id = "submit" type="submit" name="save" class="btn btn-primary col-12">Save</button>
</div>
</form>
</div>
</div>
For some reason the JavaScript code I commented out works, but it only appends "clone" to my ".container" correctly, on the next line below the form. However I want to attach it to my ".header", but it attaches next to the header, not below it. The jQuery code doesn't do anything, it doesn't attach my "clone" anywhere.
I hope I was clear. Could you please help me to find the reason of the bugs?
A few changes are needed:
The id value of the template has a hyphen which must be escaped in the selector. Two backslashes are needed in the string literal; the first is needed to actually get a backslash in the string. The remaining one will be interpreted by the selector.
Clone the row element within the template, not the template itself. However, jQuery will not know of a DOM within the template tag, so you could just take the HTML content instead of cloning, and then turn that into a jQuery object again (which produces the DOM for it).
Insert the clone just before the template
Code:
let clone = $($("#table\\-template").html()); // <--------
$("#id",clone).text(value.id);
$("#author",clone).text(value.author);
$("#title",clone).text(value.title);
$("#isbn",clone).text(value.isbn);
$("#table-template").before(clone); // <------
As others have commented, id attributes should have unique values, so your template content cannot have id properties (since it gets cloned). Use class attributes instead.
jQuery bug
Hello my friend. You are cloning the incorrect element, because your create a clone of template with the id #table-template. Please, make this change to your code:
...
let clone = $("#table-template").html();
...
The other thing, the cloned code appears next to #header and not below it because you are using a .row class. I propose to create a div below the #header, with the id="body" and append the new content inside:
...
// $("#header").append(clone);
-> $("#body").append(clone);
...
Thanks for the example.
But I don't change the id of the "collapse" div.
The rest of the objects are cloned normally.
<template id="facilities_template">
<div class="collapse">
<div class="form-check icon-check">
<input class="form-check-input" type="checkbox">
<label class="form-check-label font-14" id="facilities_name" ></label>
<i class="icon-check-1 far fa-square color-gray-dark font-20"></i>
<i class="icon-check-2 fa fa-check-square font-20 color-green-dark"></i>
</div>
<div class="mb-3"></div>
</div>
</template>
JavaScript:
let cloneFacility = $($('#facilities_template').html());
$('#facilities_name', cloneFacility).text(value.name);
$('#facilities_name', cloneFacility).attr('data-facility-id', value.id);
$('#collapse', cloneFacility).attr('id','collapse'+ value.id)
$('#facilities_template').before(cloneFacility);
$('#faсility_filter').append(cloneFacility);

Thymeleaf attribute and modal

Edited:
Just figured out that i need JS. Plase, help me with this. I have a th:attr="data-object-id=${department.id}" who store Department id, which i need to put in the modal in the <input id="ids" name="ids" type="text" class="validate">.
How will JS or JQuery looks like? I am trying to write, but all time null or undefined.
<tr th:each="department : ${departments}">
<td class="dep_id" th:text="${department.id}">1</td>
<td th:text="${department.name}"></td>
<td>
<div class="dep_edit">
<a class="settings_dep" th:href="#{'/departments/' + ${department.id} + '/'}"><i class="material-icons">settings</i></a>
<a class="edit_dep modal-trigger" href="#modal3" th:attr="data-object-id=${department.id}"><i
class="material-icons">edit</i></a>
<form method="post" th:action="#{'/departments/' + ${department.id} + '/delete'}" class="inline">
<button type="submit" value="" class="link-button delete_dep">
<i class="material-icons">delete</i>
</button>
</form>
</div>
</td>
</tr>
<div id="modal3" class="modal modal-departments">
<div class="modal-dep modal-content">
<h4>Update Department</h4>
<a href="#" class="dep-modal-close modal-close"><i
class="material-icons icon_close">close</i></a>
<p>Update Department name</p>
</div>
<div class="dep-modal">
<form id="dep-update" class="col s12" th:action="#{'/departments/update'}" method="POST">
<div class="row-modal-dep">
<div class="input-field col s6">
<input id="depName" name="name" type="text" class="validate">
<input id="ids" name="ids" type="text" class="validate">
<label for="name">Department Name</label>
<i class="edit-dep-marker material-icons prefix">mode_edit</i>
</div>
</div>
</form>
<div class="modal-footer">
<input class="modal-close waves-green green btn-dep btn" type="submit" form="dep-update">
</div>
</div>
</div>
I need to give ID value of department to MODAL, so i can update it
My Departments class is easy. Only ID and name;
The 2 tricks to achieve the same (PS - I'm not a Frontend expert):-
1.) Is to create a hidden html-element on your html page & set the value and then get the value of that element using jquery on your modal.
2.) create a function on that html-element and pass the dynamic value to it and then implement your modal hide/show code inside that function, something like this :- -
<a class="edit_dep modal-trigger" th:onclick="'javascript:showFunctionModal(\'' + ${department.id} +'\');'"><i
class="material-icons">edit</i></a>
and your function would be something like this :-
function showFunctionModal(id) {
//logic to hide & show function
}
You can listen to the show.bs.modal event and capture the department id as shown below:
$('#modal3').on('shown.bs.modal', function (e) {
var target = e.relatedTarget;
var departmentId = $(target).data('object-id');
$("#ids").val(departmentId);
});
Problem solved. Huge thanks #Sumit.
th:onclick="'javascript:showFunctionModal(\'' + ${department.id} +'\');'"> on the field which id i want to fetch and then in ready modal function set id.
function showFunctionModal(id) {
$(document).ready(function () {
$('.modal3').modal();
$("#ids").val(id);
});

Jquery does not set text box value

I am trying to set the value of a text box when file upload is selected , how ever it does not happen but I see correct value in alert box.
<div class="row">
<div class="col-xs-2">
<div class="file-label"><i></i>#Resources.FolderPath</div>
</div>
<div class="col-xs-4">
<input class=".form-control" name="fileText" type="text" />
<div class="fileUpload btn btn-primary">
<span>Browse</span>
<input type="file" name="File" id="fileUpload" class="upload"/>
</div>
</div>
<div class="col-xs-4">
<label id="fileSizeError" style="color: red"></label>
</div>
</div>
$(document).ready(function () {
$(document)
.on("change","#fileUpload",
function (e) {
alert($("#fileUpload").val());
$("#fileText").val($("#fileUpload").val());
alert("hi");
});
});
Please help me here.I am using Asp.net MVC as platform.
Your input has a name, but #fileText is an ID selector. Either add an id to it, or use an attribute selector to find it.
So either:
<input class=".form-control" id="fileText" name="fileText" type="text" />
<!-- add id------------------^^^^^^^^^^^^^ -->
or
$("[name=fileText]").val($("#fileUpload").val());
// ^^^^^^^^^^^^^^^---- use attribute selector
Try native js:
document.getElementById("fileText").defaultValue = $("#fileUpload").val();
OR
$("#fileText").attr("value", "some value");
Also;
Check to see if your original code works with replacing .val() with .text

getting wrong values when javascript data tags used to manipulate dom values on AJAX success

I am setting up a cart that has many items and a subtotal. When somebody clicks remove the item is destroyed successfully and the item successfully hidden from the view using jquery. The problem is my calculation for the subtotal in javascript is giving me crazy numbers. I calculate the subtotal using data tags to hold values and then reseting the subtotal data tag to its new value (so new removals have the correct calculations).
html
<div style="padding-top:5px;" class="container backdrop add-top">
<div class="row itemrow">
<div class="six offset-by-one columns">Pool Noodles</div>
<div class="three columns">
<ul class="unstyled cartqty">
<form accept-charset="UTF-8" action="/line_items/61" class="remove-bottom" data-remote="true" id="edit_line_item_61" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" />
<input name="_method" type="hidden" value="put" />
<input name="authenticity_token" type="hidden" value="eQhVhHqr2ZsLR1chbyngY0XRB/S40ckR4luq37qvvkc=" /></div>
<li class="magna remove-bottom">
<input class="small-input" id="line_item_quantity" name="line_item[quantity]" type="number" value="1" />
<input class="button-to-link outerspace remove-bottom" name="commit" type="submit" value="update" /></li>
</form> <li class="magna">
remove</li>
</ul>
</div>
<div class="two columns">each #$10.00</div>
<div class="two columns">= $10.00</div>
</div>
<div class="row itemrow">
<br/>
<div class="six offset-by-one columns">Javascript for Dummies</div>
<div class="three columns">
<ul class="unstyled cartqty">
<form accept-charset="UTF-8" action="/line_items/59" class="remove-bottom" data-remote="true" id="edit_line_item_59" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" /><input name="_method" type="hidden" value="put" />
<input name="authenticity_token" type="hidden" value="eQhVhHqr2ZsLR1chbyngY0XRB/S40ckR4luq37qvvkc=" /></div>
<li class="magna remove-bottom"><input class="small-input" id="line_item_quantity" name="line_item[quantity]" type="number" value="5" />
<input class="button-to-link outerspace remove-bottom" name="commit" type="submit" value="update" /></li>
</form> <li class="magna">remove</li>
</ul>
</div>
<div class="two columns">each #$10.00</div>
<div class="two columns">= $50.00</div>
</div>
<div class="row checks">
<br/>
<div class="three offset-by-eleven columns">
<span class="pull-right">
Subtotal: <span id="subtotal" data-sub="60.0">$60.00</span>
</span>
</div>
</div>
</div>
Javascript
jQuery(function() {
return $("a[data-remote]").on("ajax:success", function(e, data, status, xhr) {
e.preventDefault();
newVal = (Number($("#subtotal").data('sub')) - Number($(this).data('price'))).toFixed(2);
console.log("newval="+newVal);
$("#subtotal").html("$" + newVal);
$("#subtotal").attr('data-sub', newVal);
return $(this).closest('.itemrow').hide();
});
});
subtotal = 60.
When I delete the first object (pool noodles, full price =10.00)
Then subtotal goes to 50 (Correct) [all data attributes are as expected]
When I delete the second object (javascript for dummies, full price =50.00)
Then subtotal goes to 10 (incorrect, it should be 0) [data-sub = "10"]
Why is this happening? where is 10 coming from? Any insight is appreciated.
Is there a better way to do this using the jquery .each() method?
EDIT
I added console.log to the js in an attempt to debug. I got the following in the console:
newval=50.00
newval=50.00
newval=10.00
newval=10.00
newval=10.00
Seems weird, I'm using RoR. I have a destroy action for LineItems which responds with format.js corresponding to destroy.js.erb (where this posted js lives):
def destroy
#line_item = LineItem.find(params[:id])
#line_item.destroy
respond_to do |format|
format.html { redirect_to current_cart_url }
format.js
end
end
So, if I read right you are adding and subtracting to a total each time something is removed?
I find it's always better to recount everything, it's so much easier to maintain than a half dozen edit operations(add,delete,number change, qty change is a curve ball).
Here is a function that can add up all input's that match a selector(Your selector would obviously be different).
function add(){
var total = 0;
$('input').each(function(i,domEl){
var val = $(domEl).val();
if(!isNaN(val)){
total += parseFloat(val);
}
});
return total;
}
Quick fix is to change this:
$("#subtotal").attr('data-sub', newVal);
To this:
$("#subtotal").data('sub', newVal);
This is the answer I was looking for. Used .each() and a data-attribute for each line-item link. Data-attribute of clicked link are set to 0 on successful ajax call. Line-items are iterated through adding each data-price together and replacing subtotal with the sum.
function addItems(){
var subtotal = 0;
$('.destroyer').each(function(index){
var val = $(this).data('price');
if(!isNaN(val)){
subtotal += parseFloat(val);
}
});
return total;
}
jQuery(function() {
return $("a[data-remote]").on("ajax:success", function(e, data, status, xhr) {
e.preventDefault();
$(this).data('price', 0);
$(this).closest('.itemrow').hide();
total = addItems();
return $("#subtotal").html("$" + Number(total).toFixed(2));
});
});

Categories