Minification leads to redeclaration error in FF and IE - javascript

We encountered a problem with the minification provided by the NuGet package Microsoft.AspNet.Web.Optimization, as it seems to have problems with let. Somehow the minifier sets the name of the variables bookingDefaultIndex and i to the same name (i). This makes Firefox and IE 11 report a scope problem (Firefox reports SyntaxError: redeclaration of let i, IE 11 reports Let/Const redeclaration), because the variable was already defined. Without minification, the code works just fine in IE and FF. Chrome reports no problems with the minified code.
In the following code snippets, I marked the relevant lines with a comment that starts with // [SO-COMMENT], so you can search for that to see the problematic lines.
This is the unminified function that causes problems:
_handleDDLValuesByContext: function () {
if (this.options.isCreate) {
if (this.options.isChildCreation) {
//If we are creating a child ->
this.$ddlBookingType.val(this.options.data.BookingTypeID);
this.$ddlAllocationUnit.val(this.options.data.AllocationUnitID);
this.$ddlEffortAllocationUnit.val(this.options.data.AllocationUnitID);
if (this.options.data.ServiceCategoryID == null) {
this.$ddlServiceCategory.val('-1').trigger('change');
if (this.options.data.PricePerUnit != null) {
this.$structureRate.val(GetFormat(this.options.data.PricePerUnit));
}
} else {
this.$ddlServiceCategory.val(this.options.data.ServiceCategoryID).trigger('change');
}
//If we are creating a child, prefill his accounting type with the parent accounting type
if (this.options.data.AccountingTypeID == null) {
this.$ddlAccountingType.val('-1').trigger('change');
} else {
this.$ddlAccountingType.val(this.options.data.AccountingTypeID).trigger('change');
}
} else {
//If it's parent creation ->
let bookingTypes = this.options.structureSpecificData.BookingTypes;
let bookingDefaultID = null;
// [SO-COMMENT] the following variable is minified to 'i'
let bookingDefaultIndex = null;
for (let i = 0, len = bookingTypes.length; i < len; i++) {
if (bookingTypes[i].IsDefault) {
bookingDefaultID = bookingTypes[i].ID;
bookingDefaultIndex = i;
}
}
let allocationTypes = this.options.structureSpecificData.AllocationUnitTypes;
if (bookingDefaultID == null) {
//In case there's no default booking type id, we set the booking types, allocations and effort allocations to their first available value
this.$ddlBookingType.val(bookingTypes[0].ID);
this.$ddlAllocationUnit.val(allocationTypes[0].ID);
this.$ddlEffortAllocationUnit.val(allocationTypes[0].ID);
} else {
let allocationDefaultID = null;
this.$ddlBookingType.val(bookingDefaultID).trigger('change');
allocationTypes = [];
let bookings = this.options.structureSpecificData.BookingTypes;
let allocations = this.options.structureSpecificData.AllocationUnitTypes;
// [SO-COMMENT] this is the 'original' i
for (let i = 0, len = allocations.length; i < len; i++) {
if (allocations[i].BaseUnitID == bookings[bookingDefaultIndex].BaseUnitID) {
allocationTypes.push(allocations[i]);
}
}
for (let i = 0, len = allocationTypes.length; i < len; i++) {
if (allocationTypes[i].IsDefault) {
allocationDefaultID = allocationTypes[i].ID;
}
}
if (allocationDefaultID == null) {
this.$ddlAllocationUnit.val(allocationTypes[0].ID);
this.$ddlEffortAllocationUnit.val(allocationTypes[0].ID);
} else {
this.$ddlAllocationUnit.val(allocationDefaultID);
this.$ddlEffortAllocationUnit.val(allocationDefaultID);
}
}
this.$ddlServiceCategory.val('-1');
}
} else {
//If we are edditing ->
this.$ddlBookingType.val(this.options.data.BookingTypeID);
this.$ddlAllocationUnit.val(this.options.data.AllocationUnitID);
this.$ddlEffortAllocationUnit.val(this.options.data.AllocationUnitID);
if (this.options.data.IsParentElement) {
this.$ddlServiceCategory.val('-1').trigger('change');
//We have to check against a NaN type since the effort and the total cost can be of that type
//in case we have a structure hierarchy with an accounting type of fixed price and therefore no effort and cost
if (isNaN(this.options.structureTotalCost)) {
this.$structureTotalCost.val('');
} else {
this.$structureTotalCost.val(GetFormat(this.options.structureTotalCost));
}
if (isNaN(this.options.structureEffort)) {
this.$structureEffortUnits.val('');
} else {
this.$structureEffortUnits.val(GetFormat(this.options.structureEffort));
}
} else {
if (this.options.data.ServiceCategoryID == null) {
this.$ddlServiceCategory.val('-1').trigger('change');
if (this.options.data.PricePerUnit != null) {
this.$structureRate.val(GetFormat(this.options.data.PricePerUnit));
this._checkTotalCostCalculation();
}
} else {
if (this.options.data.PricePerUnit !== null) {
this.$structureRate.val(GetFormat(this.options.data.PricePerUnit));
this.$ddlServiceCategory.val(this.options.data.ServiceCategoryID);
this._checkTotalCostCalculation();
} else {
this.$ddlServiceCategory.val(this.options.data.ServiceCategoryID).trigger('change');
}
}
}
//Since we are editing we should prefill the accounting type with the accounting id and the fixed price too if it exists
//And not trigger anything
if (this.options.data.AccountingTypeID == null) {
this.$ddlAccountingType.val('-1').trigger('change');
} else {
this.$ddlAccountingType.val(this.options.data.AccountingTypeID).trigger('change');
}
if (isNaN(this.options.totalFixedPrice)) {
this.$fixedPrice.val('');
} else {
this.$fixedPrice.val(GetFormat(this.options.totalFixedPrice));
}
}
}
And this is the minified version:
_handleDDLValuesByContext: function() {
if (this.options.isCreate)
if (this.options.isChildCreation) this.$ddlBookingType.val(this.options.data.BookingTypeID), this.$ddlAllocationUnit.val(this.options.data.AllocationUnitID), this.$ddlEffortAllocationUnit.val(this.options.data.AllocationUnitID), this.options.data.ServiceCategoryID == null ? (this.$ddlServiceCategory.val("-1").trigger("change"), this.options.data.PricePerUnit != null && this.$structureRate.val(GetFormat(this.options.data.PricePerUnit))) : this.$ddlServiceCategory.val(this.options.data.ServiceCategoryID).trigger("change"), this.options.data.AccountingTypeID == null ? this.$ddlAccountingType.val("-1").trigger("change") : this.$ddlAccountingType.val(this.options.data.AccountingTypeID).trigger("change");
else {
let t = this.options.structureSpecificData.BookingTypes,
i = null, // [SO-COMMENT] this shouldn't be named i
r = null;
for (let n = 0, u = t.length; n < u; n++) t[n].IsDefault && (i = t[n].ID, r = n);
let n = this.options.structureSpecificData.AllocationUnitTypes;
if (i == null) this.$ddlBookingType.val(t[0].ID), this.$ddlAllocationUnit.val(n[0].ID), this.$ddlEffortAllocationUnit.val(n[0].ID);
else {
let t = null;
this.$ddlBookingType.val(i).trigger("change");
n = [];
let f = this.options.structureSpecificData.BookingTypes,
u = this.options.structureSpecificData.AllocationUnitTypes;
for (let t = 0, i = u.length; t < i; t++) u[t].BaseUnitID == f[r].BaseUnitID && n.push(u[t]);
// [SO-COMMENT] here there is a second i that causes the problem
for (let i = 0, r = n.length; i < r; i++) n[i].IsDefault && (t = n[i].ID);
t == null ? (this.$ddlAllocationUnit.val(n[0].ID), this.$ddlEffortAllocationUnit.val(n[0].ID)) : (this.$ddlAllocationUnit.val(t), this.$ddlEffortAllocationUnit.val(t))
}
this.$ddlServiceCategory.val("-1")
} else this.$ddlBookingType.val(this.options.data.BookingTypeID), this.$ddlAllocationUnit.val(this.options.data.AllocationUnitID), this.$ddlEffortAllocationUnit.val(this.options.data.AllocationUnitID), this.options.data.IsParentElement ? (this.$ddlServiceCategory.val("-1").trigger("change"), isNaN(this.options.structureTotalCost) ? this.$structureTotalCost.val("") : this.$structureTotalCost.val(GetFormat(this.options.structureTotalCost)), isNaN(this.options.structureEffort) ? this.$structureEffortUnits.val("") : this.$structureEffortUnits.val(GetFormat(this.options.structureEffort))) : this.options.data.ServiceCategoryID == null ? (this.$ddlServiceCategory.val("-1").trigger("change"), this.options.data.PricePerUnit != null && (this.$structureRate.val(GetFormat(this.options.data.PricePerUnit)), this._checkTotalCostCalculation())) : this.options.data.PricePerUnit !== null ? (this.$structureRate.val(GetFormat(this.options.data.PricePerUnit)), this.$ddlServiceCategory.val(this.options.data.ServiceCategoryID), this._checkTotalCostCalculation()) : this.$ddlServiceCategory.val(this.options.data.ServiceCategoryID).trigger("change"), this.options.data.AccountingTypeID == null ? this.$ddlAccountingType.val("-1").trigger("change") : this.$ddlAccountingType.val(this.options.data.AccountingTypeID).trigger("change"), isNaN(this.options.totalFixedPrice) ? this.$fixedPrice.val("") : this.$fixedPrice.val(GetFormat(this.options.totalFixedPrice))
}
My google searches for IIS minification scope problems didn't show any useful results. What could we try to investigate and fix this problem, other than not to use let?

Related

JavaScript If-Statement Proved True But Outputs False

I am learning JavaScript by programming my first game (a simple laser-mirror-type game). The game operates in a grid and I want to determine if a cell holds an obstacle or not. So I call this function:
function updateGrid () {
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
for (let o = 0; o < obstacles.length; o++) {
if (grid[i][j].x === obstacles[o].x && grid[i][j].y === obstacles[o].y) {
grid[i][j].obstacle = true;
} else if (grid[i][j].x != obstacles[o].x && grid[i][j].y != obstacles[o].y) {
//grid[i][j].obstacle = false;
}
}
for (let m = mirrors.length - 1; m >= 0; m--) {
if (grid[i][j].x + cellOffset.x== mirrors[m].x && grid[i][j].y + cellOffset.y == mirrors[m].y) {
grid[i][j].mirror = true;
} else {
grid[i][j].mirror = false;
}
}
if (grid[i][j].x + cellOffset.x == target.x && grid[i][j].y + cellOffset.y == target.y) {
grid[i][j].target = true;
} else {
grid[i][j].target = false;
}
if (grid[i][j].x == laserPen.x && grid[i][j].y + (rowH / 2) - (cellOffset.y / 4) == laserPen.y) {
grid[i][j].pen = true;
} else {
grid[i][j].pen = false;
}
}
}
}
However the if-statement that determines if the cell contains an obstacle, seems to not work.
This works (sets grid[ i ][ j ].obstacle to true):
for (let o = 0; o < obstacles.length; o++) {
if (grid[i][j].x === obstacles[o].x && grid[i][j].y === obstacles[o].y) {
grid[i][j].obstacle = true;
} else if (grid[i][j].x != obstacles[o].x && grid[i][j].y != obstacles[o].y) {
//grid[i][j].obstacle = false;
}
}
This does not (sets grid[ i ][ j ].obstacle to false):
for (let o = 0; o < obstacles.length; o++) {
if (grid[i][j].x === obstacles[o].x && grid[i][j].y === obstacles[o].y) {
grid[i][j].obstacle = true;
} else if (grid[i][j].x != obstacles[o].x && grid[i][j].y != obstacles[o].y) {
grid[i][j].obstacle = false;
}
}
I actually added the else-if just for safety, but it failed to work with a simple else-statement as well.
I am using the p5.js library and any insight into what is happening here would be greatly appreciated. Thanks!
Found the bug after some testing. I was iterating through all the obstacles on the same grid cell (i.e. test obstacles[0] for grid[2][2], test obstacles[1] for grid[2][2]). This meant that if the first obstacle in the array proved true, but the others proved false, the overall grid[2][2].obstacle would become false. Or to map it visually:
grid[2][1] ...
grid[2][2].obstacle = true!
grid[2][2].obstacle = false.
grid[2][2].obstacle = false.
grid[2][3] ...
Output:
grid[2][2].obstacle is false :(

Pop up a warning when the same item is entered twice on a sales order when the order is created/edited

I am trying to do a pop-up warning before the sales order is saved if the exact same item is entered twice when the order is created/modified on Netsuite. However, there is no window popping up and I am not sure what is wrong with the script. Here is what I got:
function validateitem (type){
var flag = true;
var numLine = nlapiGetLineItemCount('item');
itemArr = [];
if (type == 'item' && numLine > 0) {
for(var i = 0; i < numLine; i++) {
var itemSO = {};
itemSO.id = nlapiGetLineValue('item','item',i);
if (itemSO.id != null && itemSO.id !=''){
for (var j = 0; j < numLine; j++){
if(itenArr.indexOf(itemSO[i].id) === -1) {
itemArr.push(itemSO[i].id);}
else{
if (!confirm('You have entered a duplicate item for this sales order. Continue?'))
{
flag = false;
}
}
}
}
}
}
return flag;
}
Can somebody help, please?
Here is a slightly edited version:
function validateitem (){
var flag = true;
var numLine = nlapiGetLineItemCount('item');
itemArr = [];
if (numLine > 0) {
for(var i = 1; i <= numLine; i++) {
var itemSO = nlapiGetLineItemValue('item','item',i);
if (itemSO != null && itemSO !=''){
for (var j = 1; j <= numLine; j++){
if(itemArr.indexOf(itemSO[i]) === -1) {
itemArr.push(itemSO[i]);}
else{
flag = false;
}
}
}
}
}
if (flag == false){
alert('You have entered the same item twice.Continue?');
}
return flag;
}
This is the complete after-edit code that works:
function validateitem (){
var flag = true;
var numLine = nlapiGetLineItemCount('item');
itemArr = [];
if (numLine > 0) {
for(var i = 1; i <= numLine; i++) {
var itemSO = nlapiGetLineItemValue('item','item',i);
if (itemSO != null && itemSO !=''){
for (var j = i+1; j <= numLine; j++){
var itemSOplus = nlapiGetLineItemValue('item','item',j);
if(itemSO === itemSOplus) {
flag = false;
}
}
}
}
}
if (flag == false){
alert('You have entered the same item twice.Continue?');
}
return flag;
}
Thanks to Krypton!!
As per SuiteAnswers ID 10579, there are no paramters passed to the saveRecord client event. Therefore when your code checks the following:
if (type == 'item' && numLine > 0)
it finds that type equals undefined, so the condition is not met and the code will jump straight down to return flag which has been set to true.
Also note that in SuiteScript 1.0, line indexes start from 1 - not 0 as your code seems to assume.
EDIT - adding comment to form part of this answer:
I'd like to understand your logic behind itemSO[i] - as itemSO is not an array. Why not just compare the item from the current line of the inner loop with the current line of the outer loop and set the flag false if they match? Also, the inner loop need only start from j = i + 1 as the previous lines would have already been compared.

How to check javascript nodelist if it's contents are either all empty or all have values?

I'm fairly new to javascript and looking at checking some fields with dynamic ID's at the end of the ID to see if they've either had values entered in all of them or none of them at all. The user shouldn't be allowed to only enter values in some of them and leave others blank.
I've wrote the below, which works, but I feel there must be a better way of doing this?:
var x = document.querySelectorAll('[id^="entryField"]');
for (var i = 0; i < x.length; ++i) {
if (x[i].value == "") {
for (var i = 0; i < x.length; ++i) {
if (x[i].value != "") {
alert("Please enter a value");
}
}
}
}
One loop should work with a counter for empty (or filled) fields. If the counter is not zero and does not have the length of the object, then some fields have a value.
var x = document.querySelectorAll('[id^="entryField"]'),
empty = 0;
for (var i = 0; i < x.length; ++i) {
if (x[i].value == "") {
++empty;
}
}
if (empty !== 0 && empty !== x.length) {
alert("Please enter a value");
}
This will be a simpler version:
var x = document.querySelectorAll('[id^="entryField"]');
const inputs = Array.from(x);
const allInput = inputs.every(input => {
return (input.value != "");
});
const allEmpty = inputs.every(input => {
return (input.value == "");
});
if (allInput || allEmpty) {
alert('xxxxxx');
}
ES5 implementation:
var x = document.querySelectorAll('[id^="entryField"]');
var inputs = Array.from(x);
var allInput = inputs.every(function(input) {
return (input.value != "");
});
var allEmpty = inputs.every(function(input) {
return (input.value == "");
});
if (allInput || allEmpty) {
alert('xxxxxx');
}
EDIT: Support allInput or allEmpty. Overlooked at the beginning.
You can check with two every calls, below will be true if all elements are filled or none of the elements are filled - every other case will be false:
var x = document.querySelectorAll('[id^="entryField"]');
var allowed = function allOrNone(elements) {
return Array.prototype.every.call(x, function(v) {
return v.value && v.value != "";
}) || Array.prototype.every.call(x, function(v) {
return !v.value || v.value == "";
});
}
console.log(allowed(x));
<input id="entryFieldFoo">
<input id="entryFieldBar">

Square brackets after arguments list in JavaScript/TypeScript

Can anyone explain the meaning behind the "[0]" after the arguments list here?
let value = this.recurseMinimax(board, !player)[0];
function:
recurseMinimax(board: boolean[][], player: boolean): any {
this.numNodes++;
let winner = this.getWinner(board);
if (winner != null) {
switch (winner) {
case 1:
return [1, board];
case 0:
return [-1, board];
case -1:
return [0, board];
}
} else {
let nextVal = null;
let nextBoard = null;
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (board[i][j] == null) {
board[i][j] = player;
let value = this.recurseMinimax(board, !player)[0];
if ((player && (nextVal == null || value > nextVal)) || (!player && (nextVal == null || value < nextVal))) {
nextBoard = board.map(function (arr) {
return arr.slice();
});
nextVal = value;
}
board[i][j] = null;
}
}
}
return [nextVal, nextBoard];
}
}
And the "[1]" here:
return this.recurseMinimax(board, true)[1];
function:
minimaxMove(board: boolean[][]): any {
this.numNodes = 0;
return this.recurseMinimax(board, true)[1];
}
It Means the index of the Array (that is returning from your functions) are you accessing ... be carefully to do this without do a check maybe before, for example:
minimaxMove(board: boolean[][]): any {
this.numNodes = 0;
return this.recurseMinimax(board, true) && this.recurseMinimax(board, true).lenght>=1 ? this.recurseMinimax(board, true)[1] : {} ;
}

object doesn't support property or method 'search' ie11

I have a function in my javascript which is working fine in ie8 but not in ie11. Couldn't understand why it's giving me the error. While debugging it says"object doesn't support property or method 'search'" . Please suggest something. The fine named displayDetails.js and has code like this:
function displayTerm(paymentDropDownId) {
var locPaymentTypeId = null
var index = null;
if (null == paymentDropDownId) {
locPaymentTypeId = this.id;
} else {
locPaymentTypeId = paymentDropDownId;
}
if (null != locPaymentTypeId) {
if (locPaymentTypeId.search("1") > 0) {
index = 0;
} else if(locPaymentTypeId.search("2") > 0) {
index = 1;
} else if(locPaymentTypeId.search("3") > 0) {
index = 2;
}
}
}
Calling it like-
displayTerm(paymentDropDownId);
And
locPaymentOptions.onchange = displayTerm();

Categories