get the next element with a specific class after a specific element - javascript

I have a HTML markup like this:
<p>
<label>Arrive</label>
<input id="from-date1" class="from-date calender" type="text" />
</p>
<p>
<label>Depart</label>
<input id="to-date1" class="to-date calender" type="text" />
</p>
<p>
<label>Arrive</label>
<input id="from-date2" class="from-date calender" type="text" />
</p>
<p>
<label>Depart</label>
<input id="to-date2" class="to-date calender" type="text" />
</p>
I want to get the next element after from dates to get the corresponding to date. (Layout is a little more complex but from date has from-date class and to date has to-date class).
This is I am trying to do, I want to take a from date element and find the next element in the dom with to-date class. I tried this:
$('#from-date1').next('.to-date')
but it is giving me empty jQuery element. I think this is because next gives the next sibling matching the selector. How can I get the corresponding to-date?

Couldn't find a direct way of doing this, so wrote a little recursive algorithm for this.
Demo: http://jsfiddle.net/sHGDP/
nextInDOM() function takes 2 arguments namely the element to start looking from and the selector to match.
instead of
$('#from-date1').next('.to-date')
you can use:
nextInDOM('.to-date', $('#from-date1'))
Code
function nextInDOM(_selector, _subject) {
var next = getNext(_subject);
while(next.length != 0) {
var found = searchFor(_selector, next);
if(found != null) return found;
next = getNext(next);
}
return null;
}
function getNext(_subject) {
if(_subject.next().length > 0) return _subject.next();
return getNext(_subject.parent());
}
function searchFor(_selector, _subject) {
if(_subject.is(_selector)) return _subject;
else {
var found = null;
_subject.children().each(function() {
found = searchFor(_selector, $(this));
if(found != null) return false;
});
return found;
}
return null; // will/should never get here
}

.next('.to-date') does not return anything, because you have an additional p in between
You need .parent().next().find('.to-date').
You might have to adjust this if your dom is more complicated than your example. But essentially it boils down to something like this:
$(".from-date").each(function(){
// for each "from-date" input
console.log($(this));
// find the according "to-date" input
console.log($(this).parent().next().find(".to-date"));
});
edit: It's much better and faster to just look for the ID. The following code searches all from-dates and gets the according to-dates:
function getDeparture(el){
var toId = "#to-date"+el.attr("id").replace("from-date","");
//do something with the value here
console.log($(toId).val());
}
var id = "#from-date",
i = 0;
while($(id+(++i)).length){
getDeparture($(id+i));
}
Take a look at the example.

try
var flag = false;
var requiredElement = null;
$.each($("*"),function(i,obj){
if(!flag){
if($(obj).attr("id")=="from-date1"){
flag = true;
}
}
else{
if($(obj).hasClass("to-date")){
requiredElement = obj;
return false;
}
}
});

var item_html = document.getElementById('from-date1');
var str_number = item_html.attributes.getNamedItem("id").value;
// Get id's value.
var data_number = showIntFromString(str_number);
// Get to-date this class
// Select by JQ. $('.to-date'+data_number)
console.log('to-date'+data_number);
function showIntFromString(text){
var num_g = text.match(/\d+/);
if(num_g != null){
console.log("Your number:"+num_g[0]);
var num = num_g[0];
return num;
}else{
return;
}
}
Use JS. to get the key number from your id. Analysis it than output the number. Use JQ. selecter combine string with you want than + this number. Hope this can help you too.

I know this is an old question, but I figured I'd add a jQuery free alternate solution :)
I tried to keep the code simple by avoiding traversing the DOM.
let inputArray = document.querySelectorAll(".calender");
function nextInput(currentInput, inputClass) {
for (i = 0; i < inputArray.length - 1; i++) {
if(currentInput == inputArray[i]) {
for (j = 1; j < inputArray.length - i; j++) {
//Check if the next element exists and if it has the desired class
if(inputArray[i + j] && (inputArray[i + j].className == inputClass)) {
return inputArray[i + j];
break;
}
}
}
}
}
let currentInput = document.getElementById('from-date1');
console.log(nextInput(currentInput, 'to-date calender'));
If you know that the to date will always be the next input element with a class of "calender", then you don't need the second loop.

Related

Compare each element of one array to another and find which element is not found

I have two array which contains special characters am trying to compare each element of one array to another and get the element which is not found in another array. But my approach doesnt work properly
var specialChar = ['!','#','#','$','%','&'];
var $scope.inp= ['!','*','#'];
In my above example element '*' is not present specialChar
I tried this logic -
$scope.validateChar = function(specialChar,inp){
var i,j;
for (i=0,j=0; i<specialChar.length && j<inp.length;) {
if (specialChar[i] < inp[j]) {
++i;
} else if (specialChar[i] == inp[j]) {
++i; ++j;
} else {
$scope.notFoundChar = inp[j];
Error prompt showing special charatcter $scope.notFoundChar not found
$scope.charAllowedText = false;
return;
}
}
}
Please suggest what am doing wrong here?
You can filter out your Special char '*' like below
var result=[]
inp.map(function(inpElement){
if(specialChar.indexOf(inpElement)==-1)
result.push(inpElement)
})
console.log(result)
Below given code solves your problem.
var source = [1,2,3,4,5,6,7,8];
var target =[2,3,4,5,6,18,19];
var missingItems = [];
target.forEach(function(itemFromTarget){
var itemFound = false;
source.forEach(function(itemFromSrc){
if(itemFromTarget === itemFromSrc){
itemFound = true;
}
});
if (!itemFound) {
missingItems.push(itemFromTarget);
}
});
console.log(missingItems);

How do I replace all instances of prices (beginning with "US$") in html page using jquery?

Say I have the following HTML:
<div class="L-shaped-icon-container">
<span class="L-shaped-icon">Something is US$50.25 and another thing is US$10.99.</span>
</div>
What I'd like to do is replace all instances of US$XX.xx with GBP£YY.yy on the live page using jquery.
The value of GBP would be determined by my own currency conversion ratio.
So I'm assuming what I'd first need to do is use a regular expression to get all instances of the prices which would be anything beginning with USD$ and ending after .xx? Prices will always have cents displayed.
Then I'm stuck what would be the best way to accomplish the next part.
Should I wrap these instances in a span tag with a class, then use jquery.each() function to loop through each and replace the contents with a jquery(this).html("GBP£YY.yy")?
Any help setting me on the right path would be greatly appreciated. Thanks guys.
base method for text replacements:
var textWalker = function (node, callback) {
var nodes = [node];
while (nodes.length > 0) {
node = nodes.shift();
for (var i = 0; i < node.childNodes.length; i++) {
var child = node.childNodes[i];
if (child.nodeType === child.TEXT_NODE)
callback(child);
else
nodes.push(child);
}
}
};
stuff you need to do:
var USDinGBP = 0.640573954;
textWalker(document, function (n) {
n.nodeValue = n.nodeValue.replace(/(USD?\$(\d+(\.\d+)?))/g, function($0, $1, $2){
return "GBP£" + (parseFloat($2) * USDinGBP).toFixed(2);
})
})
you can fire that on ANY site. it will even replace titles etc.
so.. to tell you about the benefits of not using jquery for this:
jquery will process and wrap every single element in a browser compatible way.
using a native javascript solution would speed up this process alot.
using native textnodes also is benefitial since it will not break event handlers for child elements.
you should also consider using fastdom.
it does not matter if you are using jquery or native js. after writing to elements the dom has to do certain tasks before it can be read again. in the end you will loose some time for each edited element.
to give you a fastdom example:
var textWalker = function (node, callback) {
var nodes = [node];
while (nodes.length > 0) {
node = nodes.shift();
for (var i = 0; i < node.childNodes.length; i++) {
var child = node.childNodes[i];
if (child.nodeType === child.TEXT_NODE)
callback(child);
else
nodes.push(child);
}
}
};
var textReplace = function (node, regex, callback) {
textWalker(node, function (n) {
fastdom.read(function () {
var text = n.nodeValue;
if (!regex.test(text)) {
return;
}
text = text.replace(regex, callback);
fastdom.write(function () {
n.nodeValue = text;
});
});
});
};
// put this function call into your onload function:
var USDinGBP = 0.640573954;
textReplace(document, /(USD?\$(\d+(\.\d+)?))/g, function($0, $1, $2){
return "GBP£" + (parseFloat($2) * USDinGBP).toFixed(2);
});
this will basically do the job in an instant.
if you want to go even further you could add this to jquery as following:
jQuery.fn.textReplace = function (regex, callback) {
this.each(function () {
textReplace(this, regex, callback);
});
};
and call it like that:
var USDinGBP = 0.640573954;
jQuery(".L-shaped-icon").textReplace(/(USD?\$(\d+(\.\d+)?))/g, function($0, $1, $2){
return "GBP£" + (parseFloat($2) * USDinGBP).toFixed(2);
});
If all of these values are directly in the span, if not you can give them a unique class and use it to iterate over them, you can use the following
You first get the numeric part of the string in a variable
convert the currency store it in other variable.
replace US$ with GBP
replace numeric part of the string with converted value
jQuery:
("span").each(function() {
var currencyVal=$(this).text().match(/\d/);
var convertedVal=currencyVal * 100; // just for example.
$(this).text($(this).text().replace(/^US$/,'GBP£'));
$(this).text($(this).text().replace(/\d/,convertedVal));
});
I hope this will helps you. Here is working Fiddle
HTML:
<div class="L-shaped-icon-container">
<span class="L-shaped-icon">Something is US$50.25 and another thing is US$10.99.</span>
<span class="L-shaped-icon">Something is BR$20.25 and another thing is US$10.99.</span>
<span class="L-shaped-icon">Something is US$10.25 and another thing is US$10.99.</span>
<span class="L-shaped-icon">Something is US$50.20 and another thing is GR$10.99.</span>
</div>
<button class="btnUpdate">Update</button>
JavaScript Code:
function UpdateCurrency(){
var UStoGB=10;
$('span').each(function(e){
var matchedText = $(this).text().match(/US\$\S+/g);
var updatedText = $(this).text();
if(matchedText){
for(var i=0;i<= matchedText.length;i++){
if(matchedText[i]){
var currentValue=matchedText[i].replace('US$','');
if(!currentValue) currentValue=0;
var newCurrency = ( parseFloat(currentValue) * UStoGB);
updatedText= updatedText.replace(matchedText[i],'GBP£'+newCurrency);
}
}
}
$(this).text(updatedText);
});
return false;
}

How to remove all jQuery validation engine classes from element?

I have a plugin that is cloning an input that may or may not have the jQuery validation engine bound to it.
so, it's classes may contain e.g. validate[required,custom[number],min[0.00],max[99999.99]] or any combination of the jQuery validation engine validators.
The only for sure thing is that the class begins with validate[ and ends with ], but to make it more complicated as in the example above, there can be nested sets of [].
So, my question is, how can I remove these classes (without knowing the full class) using jQuery?
Here is my implementation, It's not using regex, but meh, who said it had too?
//'first validate[ required, custom[number], min[0.00], max[99999.99] ] other another';
var testString = $('#test')[0].className;
function removeValidateClasses(classNames) {
var startPosition = classNames.indexOf("validate["),
openCount = 0,
closeCount = 0,
endPosition = 0;
if (startPosition === -1) {
return;
}
var stringStart = classNames.substring(0, startPosition),
remainingString = classNames.substring(startPosition),
remainingSplit = remainingString.split('');
for (var i = 0; i < remainingString.length; i++) {
endPosition++;
if (remainingString[i] === '[') {
openCount++;
} else if (remainingString[i] === ']') {
closeCount++;
if (openCount === closeCount) {
break;
}
}
}
//concat the strings, without the validation part
//replace any multi-spaces with a single space
//trim any start and end spaces
return (stringStart + remainingString.substring(endPosition))
.replace(/\s\s+/g, ' ')
.replace(/^\s+|\s+$/g, '');
}
$('#test')[0].className = removeValidateClasses(testString);
It might actually be simpler to do that without JQuery. Using the className attribute, you can then get the list of classes using split(), and check whether the class contains "validate[".
var classes = $('#test')[0].className.split(' ');
var newClasses = "";
for(var i = 0; i < classes.length; i++){
if(classes[i].indexOf('validate[') === -1){
newClasses += classes[i];
}
}
$('#test')[0].className = newClasses
I think this solution is even more simple. You just have to replace field_id with the id of that element and if the element has classes like some_class different_class validate[...] it will only remove the class with validate, leaving the others behind.
var that ='#"+field_id+"';
var classes = $(that).attr('class').split(' ');
$.each(classes, function(index, thisClass){
if (thisClass.indexOf('validate') !== -1) {
$(that).removeClass(classes[index])
}
});

Skipping non matching strings when looping through an array in javascript

In the code below I have a form input. When the user searches for a string that happens to be in the array I want it to output the query. When a user happens to search for a string not in the array I want to output an error message. The problem is when a user searches for a string that is other than item [0] in the array (in this case ipsum) they get an error message and then they get their query returned. I want to know if this can be remedied using the code below or if a different methodology for doing this should be pursued ( I know that's an opinion ).
<form>
<input type="text" id="formInput"></input>
<input type = "button" id="search"></input>
</form>
<script>
var search = document.getElementById("search");
var data = ["lorim", "ipsum"];
search.onclick = function(){
var formInput = document.getElementById("formInput").value;
for (i=0; i<data.length; i++){
if (data[i] === formInput) {
alert(data[i]);
}
else{ alert("not working yet"); }
}
};
</script>
you don't need a loop, just use indexOf:
search.onclick = function(){
var formInput = document.getElementById("formInput").value;
if (data.indexOf(formInput) === -1) {
// they entered a bad search term
return;
}
// do the rest of your search logic
};
:) Keep at it.
The thing to remember is that you can only say 'nope didn't find it' after searching everything. So... keep a flag :)
var didntFind = true;
for (var i = 0; i < data.length; i++) {
if (data[i] === formInput) {
alert(data[i]);
didntFind = false;
break;
}
}
if (didntFind) alert('error!');
You can also check if i === data.length-1 after the loop, but the above code should be less confusing for you. Hope this helps

Fetch the data of a particular <td> in a table

I need to get the data of an particular <td>, but I don't have any id or name for that particular <td>. How do you get the contents of that <td>?
For example:
<table>
<tr><td>name</td><td>praveen</td></tr>
<tr><td>designation</td><td>software engineer</td></tr>
</table>
Is it possible to get the value "designation" from this table.. I need to extract the word "software engineer" using javascript.
I prefer to use jQuery to do all the heavy lifting for this sort of task.
For example, the following function will return the text of the next element of the same type that you're searching for:
function GetNextChildText(tagToFind, valueToFind) {
var nextText = "";
$(tagToFind).each(function(i) {
if ($(this).text() == valueToFind) {
if ($(this).next() != null && $(this).next() != undefined) {
nextText = $(this).next().text();
}
}
});
return (nextText);
}
So, for your example table, your call to return the designation could be:
var designationText = GetNextChildText('td', 'designation');
And the result is that the variable designationText would contain the value 'software engineer'.
A quick solution:
function GetTdContent(label)
{
var TDs = document.getElementsByTagName("TD");
var foundFlag = false;
for (i = 0; i < TDs.length; i++)
{
if (foundFlag) return TDs[i].innerHTML;
foundFlag = TDs[i].innerHTML.toLower() == label.toLower();
}
}
elsewhere call:
var value = GetTdContent("designation");
Explanation:
The function iterates all TDs in the document. If it finds one with the given label, say "designation", it loops one more time and returns the next TD content.
This makes a few assumptions about your source HTML. If you know your data though, it can be enough.
Something along the line of:
(not tested, just quick code to give an idea)
var tables = document.getElementById('TABLE'); // instead of document.all.tag
var rows;
var cells;
var maxCells = 1;
var designation;
if (tables) {
for (var t=0; t<tables.length; t++) {
rows = tables[t].all.tags('TR');
if (tables[t].all.tags('TABLE').length == 0) {
for (var r=0; r<rows.length; r++) {
if (rows[r].innerText != '') {
cells = rows[r].all.tags('TD');
for (var c=0; c<cells.length; c++) {
if (cells[c].innerText == 'designation' && c<(cells.length-1)) {
designation = cells[c+1].innerText;
}
}
}
}
}
}
}
Since document.all is IE specific, you should rather user getElementById, with the following to redefine that function for IE:
if (/msie/i.test (navigator.userAgent)) //only override IE
{
document.nativeGetElementById = document.getElementById;
document.getElementById = function(id)
{
var elem = document.nativeGetElementById(id);
if(elem)
{
//make sure that it is a valid match on id
if(elem.attributes['id'].value == id)
{
return elem;
}
else
{
//otherwise find the correct element
for(var i=1;i<document.all[id].length;i++)
{
if(document.all[id][i].attributes['id'].value == id)
{
return document.all[id][i];
}
}
}
}
return null;
};
}
Use XPath (tutorial here, including instructions for IE and other browsers: http://www.w3schools.com/XPath/xpath_examples.asp)
The xpath for your example is
//table/tr/td[text()="designation"]/following::td
("the td that follows the td with text "designation" that's in a tr that's in a table somewhere in the document")
Simpler Xpaths are possible - if it's the only table cell that could contain 'designation' you could use
//td[text()="designation"]/following::td
One issue with writing code to do the particular search is that it needs changing, possibly significantly, if the structure of your page changes. The Xpath may not need to change at all, and if it does, it's only one line.
Tomalak's a little quicker:
<script type="text/javascript">
function getText(tText){
var tds = document.getElementsByTagName("td");
for(var i=0, im=tds.length; im>i; i++){
if(tds[i].firstChild.nodeValue == tText)
return tds[i].nextSibling.firstChild.nodeValue;
}
}
</script>

Categories

Resources