jQuery Validation based on Next Prev values - javascript

I have ran into this problem where I am specifying a Quanitity by both Units and Price. If Units is given, price must also be supplied and if price is given, Units must also be supplied. But they are both blank, then it is ok.
+----------+-------+
| Quantity | Units |
+----------+-------+
| | |
+----------+-------+
I have used the following code to check this condition and it does work for the first instance of the classes but not the proceeding ones.
$(".Quantity").rules("add",{
required:function(element){
return $(".Quantity").next('input').val() > 0;
},
});
$(".Units").rules("add",{
required:function(element){
return $(".Units").prev('input').val() > 0;
},
});
So basically it check only the first value of occurance and not the rest. What I want is it go through complete page and compare prev next value of each occurance. In my case, data is arranged in table and each cell contains Quantity and Price input boxes which I want to retrieve by prev next. but it is not working.
Here is codepen demo. Note that I am using bootstrap dialog as well in the example which shows total number of errors and again it stops at the first instances of the class, not showing all errors because I am using class based rules. Any help would be appreciated.

With this plugin's methods, when using a selector that targets more than one element, you must enclose the method within a jQuery .each()...
$(".Quantity").each(function() {
$(this).rules("add",{
required: function(element) {
return $(".Quantity").next('input').val() > 0;
},
});
});
Otherwise, when you don't use an each(), only the first matching element is considered.

Answering it myself. I had to use the following code to fix my issue
$('.Units').each(function () {
$(this).rules("add", {
onkeyup: false,
required: function (element) {
return element.nextElementSibling.nextElementSibling.value > 0 ? true : false;
},
})
});
$('.Cost').each(function () {
$(this).rules("add", {
required: function (element) {
return element.previousElementSibling.previousElementSibling.value > 0 ? true : false;
},
})
});
The actual code I used is more complicated where prev and next values were dependent on each other.

Related

jQuery table filter not quite sorting correctly

I have been trying to use the following I found on fiddle (modified it a bit for this example). Not even sure if i'm posting this code correctly ... would be best to just look at the fiddle I guess.
{
filters[col] = text;
$(table).find('tr').each(function(i){
$(this).data('passed', true);
});
for(index in filters)
{
if(filters[index] !== 'any')
{
$(table).find('tr td:nth-child('+index+')').each(function(i){
if($(this).text().indexOf(filters[index]) > -1 && $(this).parent().data('passed'))
{
$(this).parent().data('passed', true);
}
else
{
$(this).parent().data('passed', false);
}
});
}
}
$(table).find('tr').each(function(i){
if(!$(this).data('passed'))
{
$(this).hide();
}
else
{
$(this).show();
}
});
}
Basically I will have a table with, lets say, 100 rows, and each row will have a column with a timer value in it, e.g. 10 min or 15 min. When a user clicks the appropriate "custom filter" like 10 min, the table will be filtered to only show all entries with 10min. So far it works 100%.
But, when a user might filter anything with one digit, like 5 min or 1 min it throws out, well everything for example user filters by 5 min, now it throws out 5 min, 15 min, 45 min etc.
In the example the 10, 15, 45 and 59 min filters does their job correctly. The 5 and 9 min buttons filters wrong, you will see what i mean in the example.
Are there any way to remedy that situation, so that when 5 min filter is clicked it only loads table columns with the value 5 min? I have seen something similar in another fiddle (which i can't find right now) think it was called a regular expression and not a indexOf ... this was for a search function within a table but it worked.
Please let me know if you need more information or a better description.
Here's a much simpler approach that uses filter() and eq() and only loops the rows once
function apply_filter(table, col, text) {
var $rows = $(table).find('tr');
if (text === 'any') {
$rows.show();
} else {
// hide all rows then filter the ones to show
$rows.hide().filter(function() {
return $(this).children().eq(col - 1).text().trim() === text;
}).show();
}
}
DEMO

How to modify attributes on polymer elements with javascript?

Pretty basic question, not even sure if it's polymer specific since I think i'm just lacking some basic javascript knowledge.
Anyways what I am trying to do is write a conditional statement based on the slider values entered in by the user.
If the user were to enter an amount less than 5 on the slider then a contact form would pop up
else if the sliders value is greater than 5 a list will appear.
This is what I have so far
HTML
<paper-slider id="slider" min="{{quiz.min}}" max="{{quiz.max}}" step="{{quiz.step || 1}}" immediateValue="{{value}}"></paper-slider>
JS
<script>
Polymer('topeka-quiz-picker', {
eventDelegates: {
down: 'answered',
},
quizChanged: function() {
this.value = this.$.slider.value = this.$.slider.secondaryProgress = this.quiz.min || 0;
}
});
if(this.value > 5) {
/* shows contact form */
} else {
/* shows list */
}
</script>
Edit*
What would I have to put to track the value entered by the user and how would I create an element in the else statement or go to a different card?
This is the topeka site I am trying to modify
https://polymer-topeka.appspot.com/
Use custom filters
Here is one example: Plunk
<paper-slider immediateValue="{{ val }}"></paper-slider>
{{ val | check }}
...
check: function(value) {
if (value < 100) {
return 'Value < 100';
}
return value;
},

If value is greater than, less than and becomes greater than again

I'm having a problem with my following logic.
Jsfiddle
The logic
var budgetCalc = function (financeBudget, totalCost, remainingBudget, changeOn) {
var reloadCalc = function () {
var formula = parseFloat($(financeBudget).val()) - parseFloat($(totalCost).val());
$(remainingBudget).val(Math.abs(formula.toFixed(0)));
if ( formula >= 0 ) {
$('.toolbar-budget').addClass('is-positive').append('<p>Remaining</p>');
} else {
$('.toolbar-budget').addClass('is-negative').append('<p>Over Budget</p>');
}
};
$(document).ready(function () {
// Price Input
$(changeOn).change(function () {
reloadCalc();
});
$(changeOn).trigger('change');
});
};
What works fine
The interface has multiple selects, inputs and a jQuery sliders that change the value of formula. The logic works fine when the page loads and the formula value is >= 0. If the value is < 0 than the formula works fine as well.
The Issue
If the value of the formula is < 0 and then becomes > 0 again because the user changes the values contributing to formula, the logic does not change the class back to .is-positive unless the page refreshes.
My goal
I want the class of .is-positive to be applied without the page refreshing if the value goes from < 0 to >= 0.
Seems like the simplest solution would be to remove both classes before adding the appropriate one but adding $('.toolbar-budget').removeClass('is-positive is-negative'); before your check:
$('.toolbar-budget').removeClass('is-positive is-negative');
if (formula >= 0) {
$('.toolbar-budget').addClass('is-positive').append('<p>Remaining</p>');
} else {
$('.toolbar-budget').addClass('is-negative').append('<p>Over Budget</p>');
}
jsFiddle example
You use addClass() and do not clear existing classes, so you end up with both classes set. You should remove previously set classes via removeClass() or toggleClass().
Also, I'd recommend to do the same with .append('<p>Remaining</p>'); part, so you don't just append paragraphs but swich them.

Modify function to filter by several data-attributes simultaneously

The function below allows users to filter products by data-attributes, and accommodates filtering by multiple values simultaneously. It does this by creating an array of the values selected, and when any of the values are clicked (in this case checked/unchecked) it hides all the items and then re-shows those that match the values in the updated array.
It works correctly when filtering for one data-attribute, but when combined to filter by more than one attribute it no longer shows all results matching any of the values and instead only shows results matching all the specified values.
I've posted a fiddle which demonstrates the problem here: http://jsfiddle.net/chayacooper/WZpMh/94/ All but one of the items have the values of both data-style="V-Neck" and data-color="Black" and they should therefore remain visible if either of the filters are selected, but if another value from a different data-attribute some of the items are hidden.
$(document).ready(function () {
var selected = [];
$('#attributes-Colors *').click(function () {
var attrColor = $(this).data('color');
var $this = $(this);
if ($this.parent().hasClass("active")) {
$this.parent().removeClass("active");
selected.splice(selected.indexOf(attrColor),1);
}
else {
$this.parent().addClass("active");
selected.push(attrColor);
}
$("#content").find("*").hide();
$.each(selected, function(index,item) {
$('#content').find('[data-color *="' + item + '"]').show();
});
return false;
});
$('#attributes-Silhouettes *').click(function () {
var attrStyle = $(this).data('style');
var $this = $(this);
if ($this.parent().hasClass("active")) {
$this.parent().removeClass("active");
selected.splice(selected.indexOf(attrStyle),1);
}
else {
$this.parent().addClass("active");
selected.push(attrStyle);
}
$("#content").find("*").hide();
$.each(selected, function(index,item) {
$('#content').find('[data-style *="' + item + '"]').show();
});
return false;
});
});
Both of your handlers are updating the selected array, but only one handler executes on a click. The first one if a color was (de)selected, the second if a style. Let's say you've clicked on "Black" and "Crew Neck". At that time your selected array would look like this: [ "Black", "Crew_Neck" ]. The next time you make a selection, let's say you click "Short Sleeves", the second (style) handler executes. Here's what is happening:
Short_Sleeves gets added to the selected array.
All of the items are hidden using $("#content").find("*").hide();
The selected array is iterated and items are shown again based on a dynamic selector.
Number 3 is the problem. In the above example, a style was clicked so the style handler is executing. Any items in the selected array that are colors will fail because, for example, no elements will be found with a selector such as $('#content').find('[data-style *="Black"]').show();.
I would suggest 2 things.
Keep 2 arrays of selections, one for color, one for style.
Combine your code to use only a single handler for both groups.
Here's a (mostly) working example.
Note that I added a data-type="color|style" to your .filterOptions containers to allow for combining to use a single handler and still know which group was changed.
Here's the full script:
$(document).ready(function () {
// use 2 arrays so the combined handler uses correct group
var selected = { color: [], style: [] };
// code was similar enough to combine to 1 handler for both groups
$('.filterOptions').on("click", "a", function (e) {
// figure out which group...
var type = $(e.delegateTarget).data("type");
var $this = $(this);
// ...and the value of the checkbox checked
var attrValue = $this.data(type);
// same as before but using 'type' to access the correct array
if ($this.parent().hasClass("active")) {
$this.parent().removeClass("active");
selected[type].splice(selected[type].indexOf(attrValue),1);
}
else {
$this.parent().addClass("active");
selected[type].push(attrValue);
}
// also showing all again if no more boxes are checked
if (attrValue == 'All' || $(".active", ".filterOptions").length == 0) {
$('#content').find('*').show();
}
else {
// hide 'em all
$("#content").find("*").hide();
// go through both style and color arrays
for (var key in selected) {
// and show any that have been checked
$.each(selected[key], function(index,item) {
$('#content').find('[data-' + key + ' *="' + item + '"]').show();
});
}
}
});
});
UPDATE: incorporating suggestions from comments
To make the handler work with checkboxes instead of links was a small change to the event binding code. It now uses the change method instead of click and listens for :checkbox elements instead of a:
$('.filterOptions').on("change", ":checkbox", function (e) {
// handler code
});
The "All" options "hiccup" was a little harder to fix than I thought it would be. Here's what I ended up with:
// get a jQuery object with all the options the user selected
var checked = $(":checked", ".filterOptions");
// show all of the available options if...
if (checked.length == 0 // ...no boxes are checked
|| // ...or...
checked.filter(".all").length > 0) // ...at least one "All" box is checked...
{
// remainder of code, including else block, unchanged
}
I also added an all class to the appropriate checkbox elements to simplify the above conditional.
Updated Fiddle

Show field if true, hide field if false?

Want to have a notification box displayed if amount in fieldA is higher than amount in fieldB.
Currently have some code working but the notification box toggles on and off not depending on the actual amount.
What am I missing?
jquery:
$(document).ready(function() {
$('#fieldA').change(function(){
if($(this).val()>$('#fieldb').val()){
//display it on the form
$('.labelNotification').toggle();
$('.labelNotification').append('Not recommended to have FieldA figure higher than FieldB.');
}
})
});
HTML:
< p style="display: none;" class="error labelNotification">
This is tailor-made for the toggle(boolean) method. Also, you have to be careful about appending to the notification label ... what if the user changes his answer twice? It's better to have multiple notification objects, each of which can contain stuff for a single type of notification.
$(function() {
$('#fieldA').change(function() {
var isLarger = +$(this).val() > +$('#fieldB').val(); // Note: convert to number with '+'
var $labelNotification = $('.labelNotification');
$labelNotification.toggle(isLarger);
if (isLarger) {
//display it on the form
$labelNotification.html('Not recommended to have FieldA figure higher than FieldB.');
}
})
});
If you're comparing numerical values (which it seems like you are), you should use parseInt or parseFloat to convert the (string) value returned by val() to an integer. According to the documentation for val, the function always returns a string value.
I found the problem ,
First thing is you need to have semicolon properly as below
$('#fieldA').change(function () {
if ($(this).val() > $('#fieldB').val()) {
alert("its greater");
//display it on the form
$('.labelNotification').append('Not recommended to have FieldA figure higher than FieldB.');
$('.labelNotification').show();
}
else {$('.labelNotification').hide();
$('.labelNotification').html('');}
});
Second thing , when you toggle it it won't show for the second time
if 40 > 30
and again if you entery 50 and 50 > 30 it won't show
this is second problem
final problem is empty the label all the time
$('.labelNotification').html('')'
Toggle is not the best approach for your situation.
You want to compare and then decide.
Since you are looking at numbers I would strongly suggest using a number type to do the comparison, either using parseInt() or parseFloat().
The text in the notification label only needs to be set once, since you don't have any comment for it showing something when B > A. I would suggest setting this in your HTML.
<span class="labelNotification" style="display:none">Your Warning Text</span>
<!-- if your CSS class has `display:none` remove the style attribute -->
as for the jQuery.
$(function() {
$("#fieldA").change(function() {
var a = parseInt($(this).val());
var b = parseInt($("#fieldb").val());
// handle if a or b is not a number --> isNaN(a) || isNaN(b)
if( a > b ) {
$('.labelNotification').show()
} else {
$('.labelNotification').hide()
}
});
});

Categories