Change 2 fields automatically based on each other - javascript

I am using selectize.js and I have 2 select fields:
$('#field1').selectize();
$('#field2').selectize();
and I want to change automatically value of the second, when the first field has changed (or selected); and vice versa, change value of first when value of second has changed (or selected).
I was using change function, like this:
$("#field1").change(function () {
var d = 'value-field2'
var $select_field2 = $("#id_field2").selectize();
var selectize_field2 = $select_field2[0].selectize;
selectize_field2.setValue(d);
});
$("#field2").change(function () {
var d = 'value-field1'
var $select_field1 = $("#id_field1").selectize();
var selectize_field1 = $select_field1[0].selectize;
selectize_field1.setValue(d);
});
});
But here I go in an infinite call of these 2 functions, calling each other, because they change each other.
I tried using mouseover() or click() instead of change() but didn't succed to make it work.
Any ideas?

You need some kind of variable to identify when the JavaScript is changing the value instead of the user. You could use something like this:
var programmaticallyChanging = false;
$("#field1").change(function() {
if (!programmaticallyChanging) {
var d = 'value-field2'
var $select_field2 = $("#id_field2").selectize();
var selectize_field2 = $select_field2[0].selectize;
programmaticallyChanging = true;
selectize_field2.setValue(d);
programmaticallyChanging = false;
}
});
$("#field2").change(function() {
if (!programmaticallyChanging) {
var d = 'value-field1'
var $select_field1 = $("#id_field1").selectize();
var selectize_field1 = $select_field1[0].selectize;
programmaticallyChanging = true;
selectize_field1.setValue(d);
programmaticallyChanging = false
}
});
If possible, put the var programmaticallyChanging = false; into some function so that it's not exposed on the window.

Related

Updating one element after another updates

I'm working on a page in which one element ('.item--itemprice') updates its text through another function that I'd prefer not to touch. What I'd like to do is get another element ('.header--itemprice') to update so that its text matches the first element.
Unfortunately, it seems that handler below is acting faster than the updating function. As a result, the header either stays with the previous text or changes to a blank string. Is there a way to delay the final line below until after the first element is finished updating?
$('select').on('change', function() {
const headPrice = document.querySelector('.header--itemprice');
const lowerPrice = document.querySelector('span.item--itemprice');
const $lowerText = $(lowerPrice).text();
$(headPrice).text($lowerText);
});
Here's the preexisting function:
$(document).ready( function () {
$('#txtQuantity, .ProductGroupItemQuantity').blur(updatePrice);
});
function updatePrice() {
var itemPriceEl = $('.item--itemprice');
var itemCountEl = $('#txtQuantity');
var groupUpdateEl = $('#lnkProductGroupUpdatePrice');
var groupPriceEl = $('.pdetail--price-total');
var totalPriceEl = $('.ProductDetailsPricing');
var itemPrice = moneyToNumber(itemPriceEl.text());
var itemCount = moneyToNumber(itemCountEl.val());
var itemTotalPrice = itemCount * itemPrice;
var groupTotalPrice = 0;
// Trigger Group Update
groupUpdateEl.click();
groupTotalPrice = moneyToNumber(groupPriceEl.text());
// Calculate Total Price
totalPriceEl.text('Total: $' + Number(groupTotalPrice + itemTotalPrice) / 100);
}
/*$('select').on('change', function() {
const headPrice = document.querySelector('.header--itemprice');
const lowerPrice = document.querySelector('span.item--itemprice');
const $lowerText = $(lowerPrice).text();
$(headPrice).text($lowerText);
});*/
function moneyToNumber(moneyEl) {
try {
return Number(moneyEl.replace(/[^0-9\.]+/g,"").replace(/\D/g,''));
} catch (err) {
return 0;
}
}
If you don't want to touch the other function at all and assuming it is also being called on the change event of select. A really hacky way could be, something like this -
$('select').on('change', function() {
setTimeout (function()
{
const headPrice = document.querySelector('.header--itemprice');
const lowerPrice = document.querySelector('span.item--itemprice');
const $lowerText = $(lowerPrice).text();
$(headPrice).text($lowerText);
}, 0);
});
In that case, the better way is changing the function, you can even trigger a event when the function is executed and watch this event to trigger the other function to change the element ('.header--itemprice')

How to make local varible global javascript

I have this class like so :
https://jsfiddle.net/0sh7fLtp/
When I create a new object of this class, my local variable can't be seen even when I assign to window in the class:
function Hilitor() {
var excat;
this.setMatchType = function(type) {
if (type == "exact"){
window.excat = true;
}
};
this.setRegex = function(input) {
alert(excat);
};
this.apply = function(input) {
this.setRegex();
};
}
and this is how i call it :
var myHilitor = new Hilitor();
myHilitor.apply();
myHilitor.setMatchType("exact");
Not sure I completely understand your question but you are trying to compare a variable "excat" to string "excat"... See this fiddle to how you can make your var a string and then get desired output..
https://jsfiddle.net/shemdani/0sh7fLtp/5/
var myHilitor = new Hilitor();
myHilitor.setMatchType("excat");
myHilitor.apply();
function Hilitor()
{
var excat;
this.setMatchType = function(type)
{
if(type == "excat"){window.excat = true;}
};
this.setRegex = function(input)
{
alert(window.excat);
};
this.apply = function(input)
{
this.setRegex();
};
}
Two main problems
1) Your var exact inside the function is not a global variable and so not accessible on the window object. (But that's a good thing).
Your code will work if you remove window.exact for just exact
this.setMatchType = function(type)
{
if(type == "exact"){excat = true;}
};
2) You are also calling apply before you call setMatchType. Switching them like this works:
var myHilitor = new Hilitor();
myHilitor.setMatchType("excat");
myHilitor.apply();
Working example

How can I parse a script tag, and get a variable inside of it, without using eval()?

I have a page that generates this code MULTIPLE times (content of fields array is different):
<script language="javascript">
try {
var fields = Array();
fields = {id:1,type:text,value:banana};
fields = {id:2,type:text,value:apple};
fields = {id:3,type:number,value:10};
}
</script>
Then I have a function that accesses the fields array:
function functionName(fieldId){
var allFields = eval('fields');
if (allFields) {
for ( var i = 0; i < allFields.length; i++) {
var field = allFields[i];
if(field.id == fieldId){
return field;
}
}
}
return null;
}
The problem is, that I want to use this function in multiple places, accessing the fields array of DIFFERENT script tags. Right now, that function always just gets the first script tag, and I need to be able to scope it to a specific script tag.
Since I cannot change the actual function that generates the array, I CAN change the ID of the script tag like so:
<script language="javascript" id="uniqueID">
try {
var fields = Array();
.....
}
</script>
Now I have changed the function to this:
var script = document.getElementById(uniqueID);
function functionName(fieldId){
var allFields = eval('fields'); // now here...how do I scope this by using the script var that I've created above?
....
}
So, how can I scope my allFields var to a specific script tag?
It's pretty gross, but you can use a regular expression to parse the script block, assuming it always generates it in the same format.
function functionName(scriptID, fieldID) {
var lines = $('#' + scriptID).text().split('\n')
var result;
$.each(lines, function(i, e) {
var match = e.match(/field = (\{.*\})/);
if (match) {
var obj = eval(match[1]);
if (obj.id == fieldID) {
result = obj;
return false; // Tell `$.each` to stop
}
}
}
return result;
}

Js function pass multiple parameters as a single object

I have the following constructor:
var one = new HB.hideShowFacilites.Selectors(".facilities .more-centered", "more-centered", "less-centered", "container-max-height", ".facilities .container-min-height");
Is there a way of passing all of these selectors as a single object?
HB.hideShowFacilites = HB.hideShowFacilites || {};
HB.hideShowFacilites.Selectors = function(sel1, sel2, sel3, sel4, sel5){
this.sel1 = sel1;
this.sel2 = sel2;
this.sel3 = sel3;
this.sel4 = sel4;
this.sel5 = sel5;
};
HB.hideShowFacilites.Selectors.prototype.hideShow = function(){
var $obj1 = $(this.sel1),
$obj2 = this.sel2,
$obj3 = this.sel3;
$obj4 = this.sel4,
$obj5 = $(this.sel5);
$obj1.on('click', function(e){
e.preventDefault();
if($obj1.hasClass($obj2)){
$obj1.removeClass($obj2).addClass($obj3);
$obj5.addClass($obj4);
}
else{
$obj1.removeClass($obj3).addClass($obj2);
$obj5.removeClass($obj4);
}
});
};
$(document).ready(function(){
var one = new HB.hideShowFacilites.Selectors(".facilities .more-centered", "more-centered", "less-centered", "container-max-height", ".facilities .container-min-height");
one.hideShow();
});
Depending on how HB.hideShowFacilites.Selectors is implemented, you could use Function.prototype.apply like this
function foo(args) {
var instance = Object.create(HB.hideShowFacilites.Selectors.prototype);
HB.hideShowFacilites.Selectors.apply(instance, args);
return instance;
}
var one = foo([".facilities .more-centered", "more-centered", "less-centered", "container-max-height", ".facilities .container-min-height"]);
From your edit of how it's defined, this method should work.
It is impossible in pure JS to pass in function with argument list an object with members to be treated as arguments, without modifying function like this:
HB.hideShowFacilites.Selectors = function(selectors){
this.sel1 = selectors.sel1;
this.sel2 = selectors.sel2;
this.sel3 = selectors.sel3;
this.sel4 = selectors.sel4;
this.sel5 = selectors.sel5;
};
function like this expect one argument and treat it as object with sel1, sel2 etc fields.
But in reverse it is possible to use passed argument list as array inside a function like this:
HB.hideShowFacilites.Selectors = function(sel1, sel2, sel3, sel4, sel5){
this.sel1 = arguments[0];
this.sel2 = arguments[1];
this.sel3 = arguments[2];
this.sel4 = arguments[3];
this.sel5 = arguments[4];
};
futhermore, if you do not like modify that function, it is possible to redefine it using something like this
HB.myHideShowFacilites = function(){};
HB.myHideShowFacilites.prototype = HB.hideShowFacilites;
HB.hideShowFacilites.Selectors = function(selectors){
this.sel1 = selectors.sel1;
this.sel2 = selectors.sel2;
this.sel3 = selectors.sel3;
this.sel4 = selectors.sel4;
this.sel5 = selectors.sel5;
};
and then use HB.myHideShowFacilites instead HB.hideShowFacilites

Get And Append ID in Javascript

Hey I tried this code for my project and it returns some bad results. getting the last Id does not work properly .
function regionDropDownChanged() {
var selectedRegionId = getRegionDropDown();
if (selectedRegionId !== null) {
var val = selectedRegionId[selectedRegionId.length - 1];
alert(val);
} else return;
$.get("/Common/JsonFunction/GetEnterprisesOfRegion", { regionId: val }, function (fields) {
fillDropDown(fields, getEnterpriseDropDown());
enableEnterpriseDropDown();
});
}
Also enableEnterpriseDropDown() Dropdown does not work after selecting IDs.
function enableEnterpriseDropDown() {
var enterpriseDropDown = getEnterpriseDropDown();
$(enterpriseDropDown).prop('disabled', false);
}
other methods that I use in my project
function getRegionDropDown() {
var dropDown = $("#RegionId").val();
return dropDown;
}
function getEnterpriseDropDown() {
var dropDown = $("#EnterpriseId");
return dropDown;
}
remember that I use Choosen Plugin.
Here you are using array of selectedRegionId but it is a value, as you have called getRegionDropDown() which returns a single value.
var selectedRegionId = getRegionDropDown();
So,
you may get undefined in alert in these lines
var val = selectedRegionId[selectedRegionId.length - 1];
alert(val);
If you create a Fiddle then it would be better to solve you problem.

Categories