Can this jQuery code snippet be shortened? - javascript

I have just started using jQuery and although following code gets the job done, I have a feeling that it can be shortened.
var accountAddress = $(document.createElement("input")).addClass("readOnly")
.attr("contentEditable", "false").attr("id", "d_accountAddress");
$("#customerid_c").next().next().next().append(accountAddress);
If it is not clear - what I'm doing is creating new input tag, assigning class and making it read-only, then positioning new input two TD's to the right of some known text.
Update:
This is simplified HTML that I'm modifying. The place where I add content is marked with ##1## and ##2##.
<TD id=customerid_c>
<LABEL for=customerid>Customer</LABEL>
</TD>
<TD id=customerid_d></TD>
<TD class=ms-crm-Field-Normal>
<LABEL>##1##</LABEL>
</TD>
<TD>##2##</TD>

Yes, it can.
$('#customerid_c').nextAll().eq(2)
.append('<input class="readOnly" id="d_accountAddress" />');
In jQuery 1.4.2, you can write
$('#customerid_c~:eq(2)')
.append('<input class="readOnly" id="d_accountAddress" />');
This selector, which does not work correctly in earlier versions of jQuery, uses the Next Siblings Selector (~) to select all sibling elements following #customerid_c, then uses the :eq selector to select the third (zero-based) element matched by the other selector.
jQuery has a large variety of selectors that can probably replace the indexed sibling. If you show us your HTML, we can find you one.
Other notes:
You can set multiple attributes in one call:
$(something).attr({ id: 'd_accountAddress', type: 'text' });

Related

JQuery: select element that contains an element with specific ID

Apologies if this is a duplicate. It probably is, but I've searched for this specific question and haven't been able to find it.
Let's say I have HTML like so:
<tr>
<td>
<input id="hello">
</td>
<td>
Hello
</td>
</tr>
Using JQuery or Javascript, I want to select the <tr> that contains an input with id="hello".
Here's my attempt so far:
var id = "hello";
var tr = $("tr:has('#" + id + "')");
However, this neither searches for inputs specifically nor seems to work. If you can shed some light on this I'd be very grateful.
Jasper, as haxxxton mentioned in the comments, the .closest() jQuery method is the quickest and simplest method to acheive this.
$('#hello').closest('tr');
$('input[id="hello"]').closest('tr'); // more efficient method than escaping dots if say, your id attribute had periods.
This can be done using the parents() method:
var tr = $('#hello').parents('tr');
Take a look at JQuery's closest() method here.
It traverses up the DOM tree (starting at the current element) until it hits a element which matches the given selector.
Example for your case:
$("#hello").closest("tr")
You can try to get the element by id and then closest() the parent of that element. This seems to be the prefered way in the documentation. Be aware that there can only be one id per page.
Here's an example and a link to the documentation:
var yourElement = $("#hello").closest("tr");
If you browse through the documentation you will find multiple ways of achieving the same result. Hope it helps.

jquery affect all instances of a table id

I have a table that's generated through php. Whenever "bob" is the name of the person who this data belongs to, I generate a tr id to denote that:
<tr id="0bob">...</tr>
<td>...</td>
<tr id="0bob">...</tr>
<tr id="0bob">...</tr>
<tr id="0bob">...</tr>
<tr id="0bob">...</tr>
The data inside each of the tds inside of the trs is different, and the user has to select which of these rows they want, using this checkbox:
print "<input type=\"checkbox\" id=\"check\" data-border=\"$border\" data-z=\"$z\" data-x=\"$x\" data-pn=\"$pn\" value=\"\">";
Then, in my JavaScript, I have the following line which is supposed to dim all of these lines whenever one of the checkboxes in these trs is clicked.
var pn = this.dataset.pn;
var x = this.dataset.x;
//anytime a checkbox with the id 'check' is clicked, (this is every checkbox on the page)
$('input[type="checkbox"][id="check"]').change(function() {
$( "#" + x + PN ).fadeTo( "slow" , 0.7, function() { });
}
The code, in my mind, is accurate - I'm asking for any td with the id of 0bob to be faded to 70%. The issue is that while the code "works," it only fades the first instance of this, then stops, like so:
It always fades the first instance, (red in this example,) regardless of which color the user selects, (blue, pink, or yellow).
I also can't use a tr class because I'm already using the class to change other aspects of the formatting. What am I doing wrong here?
You must use class. Ids must be unique and the browser will get angry if you duplicate them. You can pass multiple classes as follows:
<element id="some-id" class="class1 class2 class3">
From JavaScript classes can be added or removed using classList. JQuery has https://api.jquery.com/addclass/ method.
You should be using data-* attribute since ID is meant to occur once in the document. You can however work around this limitation by using an attribute selector like $('[id=0bob]'). See for example http://jsfiddle.net/Lk7dqbp6/
Your problem is that id attributes must be unique.
And the browser does that: finds the first element with that id and stops there, as it should.
Using repeated ids is invalid HTML and must be avoided like plague.
There are many alternatives for this.
I will only write the HTML structure for this.
Solution 1: a data-* attribute
You already use those, so, just use another one!
<tr data-user="bob"></tr>
These were made with the goal of providing aditional data about an element.
Solution 2: another class
You can have multiple classes per element.
Just make sure they are separated by a space:
<tr class="user-bob another-class more classes"></tr>
This may be harder to use.
Solution 3: another id schema
If you have a primary key on your SQL, you can use it to identify the user:
<tr id="user_bob_0"></tr>
<tr id="user_bob_1"></tr>
<tr id="user_bob_2"></tr>
This may be a bad idea in some situations but it will have all the data ready to use without many troubles.
Outside the scope of the answer, you have another problem:
You have this code:
var pn = this.dataset.pn;
var x = this.dataset.x;
//anytime a checkbox with the id 'check' is clicked, (this is every checkbox on the page)
$('input[type="checkbox"][id="check"]').change(function() {
$( "#" + x + PN ).fadeTo( "slow" , 0.7, function() { });
}
You see the comment?
Same problem: non-unique ids...
For this one, you would be better off using classes.
Instead of
$('input[type="checkbox"][id="check"]')
You would use
$('input.check')
Or
$('.check')
This is the right way to do it.
Also, the performance gain will be HUGE!
Attribute selectors (like [type="checkbox"] and [id="check"]) are one of the slowest selectors!
The only selectors slower than these are the pseudo-element selectors (:before, :after, ::selection, ...).
You can read more here: Is CSS faster when you are specific?
You may be thinking that this won't affect jQuery, but it will.
jQuery uses document.querySelectorAll() which runs a CSS selector in the DOM to select Javascript objects. (When it fails or isn't available, jQuery uses other methods)
Imagine your jQuery looking for over 300 elements for the selector in each of them.
Now imagine a basic table with the classes, where a few elements are connected to an entry.
See the difference?
This is the difference between your code taking 200ms and 30ms (non-measured).

checkbox selected addclass to a child

I'm trying to add a new class "ok" to an <a href> when it's checked.
I'm using bootstrap, jquery and bootstrap table from http://wenzhixin.net.cn/p/bootstrap-table.
the jsfiddle : http://jsfiddle.net/x0wegnhs/1/
Can you help me to release that ?
<tr>
<td class="bs-checkbox"><input data-index="0" name="btSelectItem" type="checkbox"></td>
<td style="text-align: left; ">file 1</td>
</tr>
Use closest to find the nearest tr, then find to find the anchor link. Use toggleClass with a boolean value to turn on/off that ok class based on the checked state.
http://jsfiddle.net/TrueBlueAussie/x0wegnhs/6/
$(':checkbox').change(function () {
$(this).closest('tr').find('td a').toggleClass('ok', $(this).is(':checked'));
});
Side notes on jQuery vs direct access:
As #Karl-André Gagnon points out this can, apparently, be shortened a little by going RAW JS for the checked property like this:
$(':checkbox').change(function () {
$(this).closest('tr').find('td a').toggleClass('ok', this.checked));
});
However, I would normally have had a variable for the $(this) element and my selector constants, so:
$this.is(checkedSelector)
becomes the following when minified:
t.is(c)
which is then actually shorter than:
this.checked
because this and the checked property cannot be minified :)
You do not need to find closest tr as somebody mentioned. You must do for each loop with jquery. When you do that, you are positioned at input tag (your "this" let me say it like that is referenced to input field when you loop). So you need first go out your input tag because you can't use next() because there is no other tags except parent tags after that input tag in that hierarchy position. That's why you need to use first parent() (to get outside where you are), so you could be positioned in td parent tag. Then you use next() to go to next td tag, and then you use find("a") to find your a tag and add to it class "ok".
$(document).ready(function(){
$("input[name=btSelectItem]").each(function () {
if (this.checked){
$(this).parent().next().find("a").addClass("ok");
}
});
});
You asked for the solution of this:
I'm trying to add a new class "ok" to an when it's checked.
You can find it here - with piece of code I described, class will be added on any a tag next to it's checkbox. You can inspect the source and see for yourself that class ok is added to checked checkbox.
http://jsfiddle.net/upquya6p/2/

How to select HTML with jQuery when it has no unique identifying attributes but has an HTML comment?

I am writing a custom script for a forum I frequently visit. It is designed to remove signatures from the board when I view it because they are distracting and annoying and they have no way to disable them in the options.
Anyway, I can run custom scripts using a helpful Chrome extension. I am able to modify any portions of the page where HTML nodes have classes, IDs, or even attributes with a little bit of unique information, but I can't seem to figure out how to select and remove the following HTML with jQuery.
<tr>
<td colspan="2">
<!--Signature-->
<div class="resultText">
<!-- sig -->
<div>Signature text</div>
<!-- / sig -->
</div>
</td>
</tr>
If there was a way I could grab the parent of <!--Signature--> that would be perfect but I'm not sure that's even possible.
There is one class resultText but that class is used wherever there is text entered by the user, not just in the signature. So I can't grab onto that.
Even if the resultText class is used elsewhere, I'd still recommend using a class selector as a starting point, otherwise you will be looking for comment nodes in the entire document.
From the matched elements, you can get their parents' contents(), use filter() to isolate the comment nodes (their nodeType property is equal to 8) and compare the value of these nodes to your Signature string:
$(".resultText").parent().each(function() {
var $this = $(this);
var signature = $this.contents().filter(function() {
return this.nodeType == 8 && this.nodeValue == "Signature";
});
if (signature.length) {
// Signature found, $this is the <td> element.
$this.closest("tr").remove(); // For example.
}
});
You can use .contents() to get all the child nodes of an element: http://api.jquery.com/contents
From the docs:
Get the children of each element in the set of matched elements,
including text and comment nodes.
$('tr').each(function (index, obj) {
$(this).children('td').contents();//this selects all the nodes in each TD element in the table, including comment nodes
});
Here is a demo: http://jsfiddle.net/NLhz9/1/
Since the script is basically just for you, use xpath to find the comments.
Try something like this:
var comment, comments = document.evaluate('//comment()', document);
while ((comment=comments.iterateNext())) {
if (comment.data=='Signature') { // found one
comment.parentNode.parentNode.removeChild(comment.parentNode);
}
}

Use jQuery to find a <tr> that is after a row with specific atribute in it

I don't know if the Title of this post makes sense, but here's a sample of what I'm working with:
<tbody>
<tr class="classRow" bgcolor="#EFE5D3" style="font-weight: bold;">
<td width="35px"><a class="classEditLink" name="33" href="#">Edit</a></td>
<td width="20px"><input type="checkbox" class="chkSelectToDelete" name="deleteClasses[]" value="33" /></td>
<td>CLASS1234</td>
<td>Class description</td>
</tr>
<tr class="classDocsRow noDocs">
<td colspan="4">
<strong>No documents are currently associated with this class.</strong>
</td>
</tr>
</tbody>
I need to remove the second row by finding it using the previous row's first <td>'s <a>'s name attribute. The psuedo code would be something like
$('.classRow a[name="' + classID + '"]').parent().parent().next().remove()
I don't know if that's proper jQuery syntax (as is, it doesn't work), but hopefully you get the point: the "starting point" of the selector is the name attribute of the <a> tag and I need to remove the following row. The <a> tag's name attribute is the only unique attribute in a given <tbody> on the page (not inlcuding the third and fourth <td>s in that row, but you get the point).
What is a properly formatted/syntaxed jQuery selector to do that?
If I understand your question correctly:
$('tr:has(a[name="33"]) + tr').remove();
Links to the corresponding JQuery documentation:
:has() Selector
Attribute Equals Selector
Next Adjacent Selector
If I've understood your question correctly, then you want something like this:
$(".classRow a[name=" + className + "]").closest("tr").next().remove();
See an example fiddle here.
you can try
$('.classRow a[name="' + classID + '"]').parents("tr").next().remove();
if it doesn't work please alert the classID to check if it's ok
Your sample works, just make sure that classID is set: working fiddle
This doesn't necessarily answer your question directly, but just a word of advice... If you have a table listing classes in each row, then it makes more sense to put everything about each individual class within the same row. So, the documents container really belongs within the class row that the documents are associated with.
The benefits to that are:
Semantic meaning and relationship association
Much easier way to reference parent/sibling/child elements
Then all you'd have to do is something like this:
$('.classRow a[name="' + classID + '"]').parent('classRow').find('.classDocs').remove();
This code works for me (tested on your HTML above):
$('.classRow a[name="' + classID + '"]')
.closest('tr')
.next()
.remove();
Also I'm not sure exactly where this code is executed in your example, but if it's supposed to happen "on load" you need to wait for the DOM to be ready:
$(function() {
// the code snippet here
});

Categories

Resources