AND/OR Conditions in jQuery - javascript

In jQuery space denotes AND condition "," denotes OR condition, Is that right? But I am facing issues in that. Here is my sample html code
<td id="4">
<div id="test1" class="test1"></div>
<div id="test2" class="test2"></div>
</td>
<td id="5">
<div id="test1" class="test1"></div>
<div id="test2" class="test2"></div>
</td>
If I use the following query, it works
jQuery('#4 [id*=test1]')
it selects the correct div. However, if I use this query,
jQuery('#4 #test1')
it doesn't work. Any Idea?

It is not valid to have duplicate ids within the same document.
If you are building this dynamically then try prepending the parent id to the child so it would be like:
<td id="r4">
<div id="r4_test1" class="test1"></div>
<div id="r4_test2" class="test2"></div>
</td>
<td id="r5">
<div id="r5_test1" class="test1"></div>
<div id="r5_test2" class="test2"></div>
</td>
Note, starting an ID with a number is also invalid, so I took the liberty to prepend "r" to your row ids.
I would recommend using the selector:
$('#r5 .test1')

Space isn't strictly an 'and' condition.
In your own example, jQuery('#4 #test1') space means to get children of #4 called #test1 if you see what I mean
The jquery docs for this explain it better than I do!
jQuery('ancestor descendant')
Selects all elements that are descendants of a given ancestor.

Thinking of selectors in terms of "AND" and "OR" probably isn't the most helpful way to go about things. If a space actually meant "AND", then these two statements would be identical:
$('.parent_class .child_class')
$('.child_class .parent_class')
If a selector was a simple "AND", then these statements would select all items that meet both criteria.
In reality, these statements are very different. A space in jQuery and CSS selectors actually shows inheritance. When you have two separate classes, as in my example, you're always saying "select the class that is second in the list, only if it is contained by an element with the first class in the list."
You could say that a comma means "OR", but really it just separates two selecting statements from each other, so that you can select two completely separate items or groups of items.
The jQuery selector syntax borrows from CSS, so this group of tutorials on w3schools.com might be a helpful place to start.

I think you ought to drop the ids off the div tags and just work with classes.
use $('#d5 .test1') or
$('#d5').find('.test1')
I usually use the latter because it's just easier to read when I go back a month later to look at the code.
<td id="d4">
<div class="test1">w</div>
<div class="test2">x</div>
</td>
<td id="d5">
<div class="test1">y</div>
<div class="test2">z</div>
</td>

Related

JQuery - Find values of elements based on other relative elements?

I'm attempting to find the value of an element (input element) based on a nearby element, specifically in my example I'm looking to return 'Complete' based on it being next to the 'Contract Review Status' field. I cannot use any unique identifier, as my source system will randomise the unique identifier.
<td class=" FieldLabel ml-FldLbl ml-BrdRight lo_51395 ml-BrdBottom" style="width:15%;">
<span id="loitem51395">
<img id="22508requiredImg" class="required-icon" src="/BackgroundImageGenerator.axd?className=Bullet&classProperties=bulletShape:RequiredIndicatorWidget;baseColor:%23B80000" alt="Required" style="display:none;">
Contract Review Status:
</span>
</td>
<td class="ml-FldCnt lo_51395 ml-BrdBottom" style="width:35%;">
<div id="master_DefaultContent_rts_s8307_f22508c" class="ArcherTreeView DisabledTree">
<ul class="rtUL rtLines">
<li id="" class="rtLI rtFirst rtLast">
<div class="rtMid">
<div data-valueslistvalueid="81019" style="color:#000000;">
<input name="master$DefaultContent$rts$s8307$ctl10" type="hidden" class="readOnly" value="81019">
Complete
</div>
</div>
</li>
</ul>
</div>
</td>
I'll be looking to store the 'Complete' in a variable so that I can display conditional graphics, depending on the current status.
Thanks in advance!
As it seems you can find the "Contract Review Status", I'd suggest you go up from there to the parentNode's in turn until you find the first td (check jQuery's "closest" method). From there take the next td (check jQuery's "next" method) and down until you find your input element (check jQuery's "find" method).
I hope this is enough information to help you solve your issue.
select the column based on the type of the input type;
$('tr > td').find('input[type=hidden]').val()
Hope this helps

Nested ng-repeat with dynamic input

I am trying to display a JSON response in a table using ng-repeat. The problem is that not all objects recieved are the same. All of them have a date, short message and long message. There are also ones with an additional value list, differing in length. This list should be diplayed underneath the long message within its own table or list. I use the alert.slice().reverse() because I want the newest entries to be on top. The new objects are inserted using .push({values}).
<tbody class="AlTbody" ng-repeat="alerts in alerts.slice().reverse()" ng-class="className">
<tr class="Altr Aldate">
<td ng-show="{{alerts.Date}}"><b>{{alerts.Date}}:</b>
</td>
</tr>
<tr class="Altr Alshort " ng-click="toggleDetail($index)">
<td>{{alerts.S}}</td>
</tr>
<tr class="Altr " ng-show="activePosition == $index">
<td class="msgL">{{alerts.L}}
<!-- 1) <p ng-show="{{item.List}}"><br><ul><li>Previous values:</li> <li ng-repeat="vals in ValueList">{{vals.value}}</li></ul> </p>-->
<!-- 2) <p ng-show="{{List.txt}}"> <br><ul><li>Previous values:</li> <li ng-repeat="List in alerts.List">{{List.txt}}</li></ul> </p>-->
</td>
</tr>
</tbody>
I already tried two approaches as seen in the code. The first one displayed the list correct however it was displayed underneath every long message instead of only the one it belongs to. I used a new variable.
var l=valList.length;
scope.List=true;
while(l>-1){
scope.ValueList.push({value: valList[l]});
l--;
}
The second approach did not work at all because I could not find an index.
var l=valList.length;
var indexV= jQuery.inArray(currdate,scope.alerts.Date);
while(l>-1){
scope.alerts[indexV].List.push({txt: valList[l]});
l--;
}
edit:
This is the current output. There you can see two objects( date, short message and long message) and both of them have the previous values section. However only the upper object is supposed to diplay the list of previous values.
What you are trying to achieve is entirely possible, my advice is to start at a known point and work from there.
I have put together a jsfiddle to show you how nested ng-repeats will work. try and work from that point. As a side note it looks like your JSON structure is overly complex, if you can simplify that down I would.
https://jsfiddle.net/roscorcoran/wyu7tgxm/
<div ng-app="App" ng-controller="Ctrl1">
<div ng-repeat="alert in alerts">
<a ng-if="alert.Date">{{alert.Date}}</a>
<p ng-repeat="val in alert.L.vals">
<a ng-if="val && val.value">{{val.value}}</a>
</p>
<p ng-repeat="item in alert.List">
<a ng-if="item && item.txt">{{item.txt}}</a>
</p>
</div>
</div>
You can try to add a ng-if statement inside the ng-repeat loop:
<p ng-if="{{values.list}}"><br><ul><li>Previous values:</li> <li ng-repeat="vals in values.list">{{vals.value}}</li></ul> </p>-->
Okay so this works for me now. It still always displays "Previous Values:" but the values only display when they actually belong to the message.
<ul ng-if="alerts.List.vals"><li>Previous values:</li> <li ng-repeat="val in alerts.List.vals" >{{val.value}}</li></ul>
This might not be the best and most elegant solution but it works.
if(valList){
scope.alerts.push({Date:currdate,S:msgSn,L:msgLn, List:{ vals:[{value:valList[0]},{value:valList[2]},{value:valList[4]},{value:valList[6]}] } });
}else{
scope.alerts.push({Date:currdate,S:msgSn,L:msgLn });
}
I only display the even indexes of the value array because the list of values was a string which I split and every uneven entry is "):" which I don't need to display.

AngularJS Data Binding Breaks ngRepeat + Strange Behavior

Background: I'm a systems guy who switched to Front End development. Just dorking around with Angular. Got creative with data binding and now I'm trying to understand this behavior:
<div ng-app>
<div class="container">Name
<input type="text" ng-model="user.name">
</div>{{ user.name }}
<div class="container">Name
<input type="text" ng-model="user.name">
</div>
<ul ng-model="user.name">
<li ng-repeat="l in user.name">{{ l }}</li>
</ul>
</div>
http://jsfiddle.net/Lpm74dd8/
I would expect this to take my input from either box, mirror the text between the input boxes, and repeat each letter on its own line at the bottom.
If I type "test" in one of the inputs, ng-repeat will break when a letter repeats.
Typing the alphabet sequentially works as I expect.
Why does ng-repeat break when input letters are duplicated? I have no practical use for this, I was just experimenting with Angular for fun and came across this and don't understand it.
ng-repeat will not accept duplicate entries. As test has t as duplicate entry, it will fail.
Add track by expression to avoid this.
When we do not provide any track by expression the entry(in this case each letter) itself is treated as a unique identifier to link the entry to the list to track the changes in it.
<li ng-repeat="l in user.name track by $index">{{ l }}</li>
Usetrack by $index with ng-repeat for dupilcate entries in array. Try this fiddle http://jsfiddle.net/1Lw11bqr/

JQuery: elegant way to replace set of elements with another set?

I have a bunch of DOM like
<div>
<div class="stuff"/>
<div class="stuff"/>
<div class="stuff"/>
</div>
and I want to replace it with a new set of stuff
<div>
<div class="stuff"/>
<p class="stuff"/>
<ul class="stuff"/>
<a class="stuff"/>
</div>
Which will be fetched via Ajax. My question is: what is the best way to do this?
$.replaceWith doesn't quite do what I want, because I then end up with multiple copies of the new stuff.
I can guarantee that all the stuff will be in one contiguous block, and so presumably I could put in some placeholder after the last element (or before the first element) of the old stuff, remove the old stuff, and replace the placeholder with the new stuff.
However, this seems rather roundabout and inelegant. Is there any clever way of, removing all the old stuff and putting in a single copy of the new stuff, all at one go?
EDIT: I would also like to do this without using any container divs. Using container divs would work in the above case, but would fail in some cases, like when the stuff is inside a <table>:
<table>
<head/>
<body>
<tr/>
<tr class="stuff"/>
<tr class="stuff"/>
<tr class="stuff"/>
<tr/>
</body>
</table>
If i want to replace the rows labelled stuff with another set of rows, possibly more, possibly fewer, there is no way I can nicely put them in a container thingy without breaking the HTML, since the <body> can only contain <tr>s (IIRC).
$('#outerdiv').empty().append(newContent);
Unlike .html(), this will work regardless of whether newContent is an HTML string, or an existing DOM structure.
If there are multiple elements to be replaced but where you need to retain their siblings, you can do this:
$('.stuff').first().before(newContent).end().remove();
i.e. take the first .stuff element, add the new content before it, and then remove all the .stuff elements.
Yes: $('#tagetDiv').html(newContent)
One way to do it would be with wrapAll:
$('.stuff').wrapAll('<div/>').parent().replaceWith('<div class="stuff"/>');
I'm not sure if that passes the "elegant" test, but it does work regardless of whether there is any other content in the containing element.
With that said, though, this seems to be a very complicated solution to a simple problem. The simple solution would be to wrap your elements in a containing element; this shouldn't be a problem if, as you say, you can guarantee that they will always be together.

How do I get the content of a <td> using JavaScript?

My HTML
<tr class="g1">
<td id="saveursqte_box[]">
<div class="t">
xxxxxxxxxxxxx
<div class="r">
<div class="a">
</div>
<img src="images/saveurs/saveur_test.jpg" width="125" border=0>
</div>
</div>
</td>
<td class="i">
<input type="text" name="saveursqte[]" alt="2.95" value="" size="3" onBlur="__sumform();">
</td>
</tr>
What I'm trying to do
I want to get the contents of: <td id="saveursqte_box[]"> using javascript.
which is:
<div class="t">
xxxxxxxxxxxxx
<div class="r">
<div class="a">
</div>
<img src="images/saveurs/saveur_test.jpg" width="125" border=0>
</div>
</div>
I tried this javascript:
var saveursqte_box = document.getElementsById('saveursqte_box[]');
and then
htmltotal = htmltotal + saveursqte_box[i].innerHTML;
but javascript doesn't seem to like me :-(
It is document.getElementById no "s".
This document.getElementById('saveursqte_box[]'); returns a single dom element not an array like jQuery.So the code to get the innerHTML would be:
htmltotal += saveursqte_box.innerHTML;
In addition to #scrappedcola's note about there being no 's' in getElementById, you may also be having problems using square brackets in the element id.
I ran your example in Firefox 4 with <td id="saveursqte_box"> and it worked, whereas using <td id="saveursqte_box[]"> I got NULL as the result of getElementById().
Also:
saveursqte_box[i]
i is not defined. Just use saveursqte_box
Thanks to all! I know my Javascript skills are low but by combining your answers together I came with this and it works perfectly :
htmltotal += document.getElementById('saveurmoisqte_box_' + i).innerHTML;
As per your answer, I removed the "s" of getElementById. My bad: I copied getElementsByName and then replaced the Name by Id... This is why there was a "s" there. The kind of mistake that can waste you a week to debug... 
After that, I rename my <td id="extrasqte_box[]"> with <td id="extrasqte_box_0">. I thought you could write ids arrays like you do with names (ex: name="xxxx[]") and then iterate but I was wrong.
With that in place it works perfectly! Not bea-u-tiful but it works.
What I'm actually doing with this is:
I have an order form with many items and when you fill an input (quantity), an hover image of the product appears to its right... and when you move away (onBLur), the form total is updated, AND using the function here above, I get the content of the <td> (including the hover image) and put a summary of the items chosen in the "checkout section". The result is super-clean for the user and user-friendly. The inconvenient is I hope this makes sense to you.

Categories