Can someone please check my code in the codePen?
After adding the item to the list, It should log the total budget in the console.
It is only showing 0. Please see the code in the codePen console.
https://codepen.io/crazydeveloper/pen/KbKvMp
budCalc: function() {
var budget, percent, totalInc, totalExp;
totalInc = data.totals.inc;
totalExp = data.totals.exp;
budget = data.totals.inc - data.totals.exp;
percent = (data.totals.exp / data.totals.inc)*100
console.log(budget);
///////// BUDGET CONTROLLER ////////
var budgetController = (function() {
var Expence = function(id, des, value) {
this.id = id;
this.des = des;
this.value = value;
}
var Income = function(id, des, value) {
this.id = id;
this.des = des;
this.value = value;
}
var data = {
allItems: {
inc: [],
exp: []
},
totals: {
inc: 0,
exp: 0,
budget: 0,
percent: 0
}
}
return {
addItem: function(type, des, val) {
var newItem, id;
if (data.allItems[type].length > 0) {
var id = data.allItems[type][data.allItems[type].length - 1].id +
1;
} else {
id = 0;
}
if (type === "exp") {
newItem = new Expence(id, des, val);
} else if (type === "inc") {
newItem = new Income(id, des, val);
}
data.allItems[type].push(newItem);
return newItem;
},
calcTotal: function(type) {
sum = 0;
data.allItems[type].forEach(function() {
sum += data.totals[type];
data.totals[type] = data.totals[type] + sum;
}
)
},
budCalc: function() {
var budget, percent, totalInc, totalExp;
totalInc = data.totals.inc;
totalExp = data.totals.exp;
budget = data.totals.inc - data.totals.exp;
percent = (data.totals.exp / data.totals.inc)*100
console.log(budget);
var getBudget = function() {
return {
totalInc: totalInc,
totalExp: totalExp,
totalBudget: budget,
percent: percent
}
}
},
testing: function() {
console.log(data);
}
}
}());
////////// UI CONTROLLER //////////////
var UIController = (function() {
var DOMs = {
inpType: ".add__type",
inpDes: ".add__description",
inpVal: ".add__value",
inpBtn: ".add__btn",
incCon: ".income__list",
expCon: ".expenses__list"
}
return {
getInp: function() {
return {
type: $(DOMs.inpType).val(),
des: $(DOMs.inpDes).val(),
val: parseFloat($(DOMs.inpVal).val())
}
},
addListItem: function(obj, type) {
var html, newHTML, ele;
if(type === "inc") {
ele = DOMs.incCon;
html = '<div class="item clearfix" id="income-%id%"><div
class="item__description">%des%</div><div class="right clearfix"><div
class="item__value">+ %val%</div><div class="item__delete"><button
class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
</div></div></div>';
} else if(type === "exp") {
ele = DOMs.expCon;
html = '<div class="item clearfix" id="expense-%id%"><div
class="item__description">%des%</div><div class="right clearfix"><div
class="item__value">- %val%</div><div class="item__percentage">21%</div>
<div
class="item__delete"><button class="item__delete--btn"><i class="ion-ios-
close-outline"></i></button></div></div></div>';
}
newHTML = html.replace("%id%", obj.id);
newHTML = newHTML.replace("%des%", obj.des);
newHTML = newHTML.replace("%val%", obj.value);
$(ele).append(newHTML);
this.clearFields();
},
clearFields: function() {
$(DOMs.inpDes).add(DOMs.inpVal).val("");
$(DOMs.inpDes).focus();
},
getDOM: function() {
return DOMs;
}
}
}
());
////////// MAIN CONTROLLER /////////
var controller = (function(budgetCtrl, UICtrl) {
var eventLis = function() {
var DOM = UICtrl.getDOM();
$(DOM.inpBtn).on("click", eventBtn);
$("html").on("keypress", function() {
if (event.keyCode === 13 || event.which == 13) {
eventBtn();
}
})
}
function eventBtn() {
var input = UICtrl.getInp();
if(input.des !== "" && !isNaN(input.val) && input.val > 0) {
var newItem = budgetCtrl.addItem(input.type, input.des, input.val);
UICtrl.addListItem(newItem, input.type);
}
budgetCtrl.budCalc();
}
return {
init: function() {
console.log("Application started!");
eventLis();
}
}
})(budgetController, UIController);
controller.init();
This is all JavaScript code. But I can's figure out why my budget is not updating?
If you check the full data structure object at this point
budCalc: function() {
var budget, percent, totalInc, totalExp;
//here
console.log(data);
totalInc = data.totals.inc;
totalExp = data.totals.exp;
budget = data.totals.inc - data.totals.exp;
percent = (data.totals.exp / data.totals.inc)*100
}
You will see that data.total attributes are setted to zero everytime
Related
I've been sitting here for a solid hour and I can't figure out what's wrong.
I'm a newbie so please don't judge.
var budgetController = (function() {
var Expense = function(id, description, value) {
this.id = id;
this.description = description;
this.value = value;
};
var Income = function(id, description, value) {
this.id = id;
this.description = description;
this.value = value;
};
var data = {
allItems: {
exp: [],
inc: []
},
totals: {
exp: 0,
inc: 0
}
};
return {
addItem: function(type, des, val) {
var newItem, ID;
if (data.allItems[type].length > 0) {
ID = data.allItems[type][data.allItems[type].length - 1].id + 1;
} else {
ID = 0;
}
if (type === 'exp') {
newItem = new Expense(ID, des, val);
} else if (type === 'inc') {
newItem = new Income(ID, des, val);
}
data.allItems[type].push(newItem);
return newItem;
},
addListItem: function(obj, type) {
var html, newHTML, element;
if (type === 'inc') {
element = DOMstrings.incomesContainer;
html = '<div class="item clearfix" id="income-%id%"><div class="item__description">%description%</div><div class="right clearfix"><div class="item__value">%value%</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>';
} else if (type === 'exp') {
element = DOMstrings.expensesContainer;
html = '<div class="item clearfix" id="expense-%id%"><div class="item__description">%description%</div><div class="right clearfix"><div class="item__value">%value%</div><div class="item__percentage">21%</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>';
}
newHTML = html.replace('%id%', obj.id);
newHTML = html.replace('%description%', obj.description);
newHTML = html.replace('%value%', obj.value);
document.querySelector(element).insertAdjacentHTML('beforeend', newHTML);
}
};
})();
var UIController = (function() {
var DOMstrings = {
inputType: '.add__type',
inputDescription: '.add__description',
inputValue: '.add__value',
inputBtn: '.add__btn',
incomesContainer: '.income__list',
expensesContainer: '.expenses__list'
};
return {
getInput: function() {
return {
type: document.querySelector(DOMstrings.inputType).value,
description: document.querySelector(DOMstrings.inputDescription).value,
value: document.querySelector(DOMstrings.inputValue).value
};
},
getDOMstrings: function() {
return DOMstrings;
}
};
})();
var controller = (function(budgetCtrl, UICtrl) {
var setupEventListeners = function() {
var DOM = UICtrl.getDOMstrings();
document.querySelector(DOM.inputBtn).addEventListener('click', ctrlAddItem);
document.addEventListener('keypress', function(event) {
if (event.keyCode === 13 || event.which === 13) {
ctrlAddItem();
}
});
};
var ctrlAddItem = function() {
var input, newItem;
input = UICtrl.getInput();
newItem = budgetCtrl.addItem(input.type, input.description, input.value);
UICtrl.addListItem(newItem, input.type);
};
return {
init: function() {
setupEventListeners();
}
};
})(budgetController, UIController);
controller.init();
addListItem function won't work. I checked the budgetController function - nothing suspicious, nothing was wrong in there, yet I get the error in the console when I call it in the controller function saying:
Uncaught TypeError: UICtrl.addListItem is not a function
at HTMLButtonElement.ctrlAddItem (app.js:108)
I want to create javascript scripts using OOP and I've done one working class calculator, but I seem it's not done in correct way.
This is code of my class
class CalculatorTable {
constructor(
aWeight1,
aWeight2,
aWeight3,
sTotalPrice = "",
sTotalGram = "",
sWeight = "",
sPrice = "",
sPrice1 = "",
sPrice2 = "",
sPrice3 = "",
sPriceForGram = "",
sWeightToPrice = ""
) {
// selectors
this.sTotalPrice = sTotalPrice;
this.sTotalGram = sTotalGram;
this.sWeight = sWeight;
this.sPrice = sPrice;
this.sPrice1 = sPrice1;
this.sPrice2 = sPrice2;
this.sPrice3 = sPrice3;
this.sPriceForGram = sPriceForGram;
this.sWeightToPrice = sWeightToPrice;
this.aWeight1 = aWeight1;
this.aWeight2 = aWeight2;
this.aWeight3 = aWeight3;
this.price = 0;
this.totalGram = 0;
this.totalPrice = 0;
this.changeWeight();
}
changeWeight() {
var thisClass = this; //it's reference
$(this.sWeight).on('change keyup paste', function(event) {
thisClass.weight = $(this).val();
// console.log("thisClass.weight="+thisClass.weight);
thisClass.price1 = $(this).data(thisClass.sPrice1);
thisClass.price2 = $(this).data(thisClass.sPrice2);
thisClass.price3 = $(this).data(thisClass.sPrice3);
thisClass.priceForGram = $(this).data(thisClass.sPriceForGram);
thisClass.setPrice();
$(this).closest('tr').find('td span.price').text(thisClass.price);
// console.log("thisClass.price="+this.price);
thisClass.setTotalGram();
thisClass.setTotalPrice();
// console.log(thisClass.price1+' '+thisClass.price2+' '+thisClass.price3+' ff'+thisClass.priceForGram);
});
}
setPrice() {
this.price = 0;
if (this.weight >= this.aWeight1[0] && this.weight <= this.aWeight1[1]) {
this.price = this.weight * this.price1;
} else if (this.weight >= this.aWeight2[0] && this.weight <= this.aWeight2[1]) {
this.price = this.weight * this.price2
} else if (this.weight >= this.aWeight3[0] && this.weight <= this.aWeight3[1]) {
this.price = this.weight * this.price3;
}
}
setTotalGram() {
var thisClass = this;
thisClass.totalGram = 0;
$(this.sWeight).each(function(index, el) {
if ($(this).val().length !== 0) {
thisClass.totalGram += parseFloat($(this).val());
}
});
$(this.sTotalGram).text(this.totalGram);
}
setTotalPrice() {
var thisClass = this;
thisClass.totalPrice = 0;
$(this.sPrice).each(function(index, el) {
if ($(this).text().length !== 0) {
thisClass.totalPrice += parseFloat($(this).text());
}
});
$(this.sTotalPrice).text(this.totalPrice.toFixed(2));
}
}
var calculator = new CalculatorTable(
[1, 100], [101, 400], [401, 1000],
'span.total-price',
'span.total-gram',
'input[name=weight]',
'span.price',
'price1',
'price2',
'price3',
'price-for-gram',
'td span.price'
);
console.log(calculator);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Can I do code like this?
I interesting call this both functions
thisClass.setTotalGram();
thisClass.setTotalPrice();
is it right way I did it?
I upgrade magento from 1.8.1 to 1.9.0, and I have a problem with one js file:
TypeError: $(...) is null
$('product_addtocart_form').getElements().each(function(el) {
simple_product_pricing.js (line 1131, col 5)
I think this file is related to the Ayasoftware_SimpleProductPricing, maybe someone can help me to solve this. Before upgrade in 1.8.1 version everything was fine, in 1.9.0 version I have this error.
I will add here the entire js:
/*
Some of these override earlier varien/product.js methods, therefore
varien/product.js must have been included prior to this file.
some of these functions were initially written by Matt Dean ( http://organicinternet.co.uk/ )
*/
Product.Config.prototype.getMatchingSimpleProduct = function(){
var inScopeProductIds = this.getInScopeProductIds();
if ((typeof inScopeProductIds != 'undefined') && (inScopeProductIds.length == 1)) {
return inScopeProductIds[0];
}
return false;
};
/*
Find products which are within consideration based on user's selection of
config options so far
Returns a normal array containing product ids
allowedProducts is a normal numeric array containing product ids.
childProducts is a hash keyed on product id
optionalAllowedProducts lets you pass a set of products to restrict by,
in addition to just using the ones already selected by the user
*/
Product.Config.prototype.getInScopeProductIds = function(optionalAllowedProducts) {
var childProducts = this.config.childProducts;
var allowedProducts = [];
if ((typeof optionalAllowedProducts != 'undefined') && (optionalAllowedProducts.length > 0)) {
allowedProducts = optionalAllowedProducts;
}
for(var s=0, len=this.settings.length-1; s<=len; s++) {
if (this.settings[s].selectedIndex <= 0){
break;
}
var selected = this.settings[s].options[this.settings[s].selectedIndex];
if (s==0 && allowedProducts.length == 0){
allowedProducts = selected.config.allowedProducts;
} else {
allowedProducts = allowedProducts.intersect(selected.config.allowedProducts).uniq();
}
}
//If we can't find any products (because nothing's been selected most likely)
//then just use all product ids.
if ((typeof allowedProducts == 'undefined') || (allowedProducts.length == 0)) {
productIds = Object.keys(childProducts);
} else {
productIds = allowedProducts;
}
return productIds;
};
Product.Config.prototype.getProductIdOfCheapestProductInScope = function(priceType, optionalAllowedProducts) {
var childProducts = this.config.childProducts;
var productIds = this.getInScopeProductIds(optionalAllowedProducts);
var minPrice = Infinity;
var lowestPricedProdId = false;
//Get lowest price from product ids.
for (var x=0, len=productIds.length; x<len; ++x) {
var thisPrice = Number(childProducts[productIds[x]][priceType]);
if (thisPrice < minPrice) {
minPrice = thisPrice;
lowestPricedProdId = productIds[x];
}
}
return lowestPricedProdId;
};
Product.Config.prototype.getProductIdOfMostExpensiveProductInScope = function(priceType, optionalAllowedProducts) {
var childProducts = this.config.childProducts;
var productIds = this.getInScopeProductIds(optionalAllowedProducts);
var maxPrice = 0;
var highestPricedProdId = false;
//Get highest price from product ids.
for (var x=0, len=productIds.length; x<len; ++x) {
var thisPrice = Number(childProducts[productIds[x]][priceType]);
if (thisPrice >= maxPrice) {
maxPrice = thisPrice;
highestPricedProdId = productIds[x];
}
}
return highestPricedProdId;
};
Product.OptionsPrice.prototype.updateSpecialPriceDisplay = function(price, finalPrice) {
var prodForm = $('product_addtocart_form');
jQuery('p.msg').hide();
jQuery('div.price-box').show();
var specialPriceBox = prodForm.select('p.special-price');
var oldPricePriceBox = prodForm.select('p.old-price, p.was-old-price');
var magentopriceLabel = prodForm.select('span.price-label');
if (price == finalPrice) {
//specialPriceBox.each(function(x) {x.hide();});
magentopriceLabel.each(function(x) {x.hide();});
oldPricePriceBox.each(function(x) { x.hide();
// x.removeClassName('old-price');
// x.addClassName('was-old-price');
});
jQuery('.product-shop').removeClass('sale-product') ;
}else{
specialPriceBox.each(function(x) {x.show();});
magentopriceLabel.each(function(x) {x.show();});
oldPricePriceBox.each(function(x) { x.show();
x.removeClassName('was-old-price');
x.addClassName('old-price');
});
jQuery('.product-shop').addClass('sale-product') ;
}
};
//This triggers reload of price and other elements that can change
//once all options are selected
Product.Config.prototype.reloadPrice = function() {
var childProductId = this.getMatchingSimpleProduct();
var childProducts = this.config.childProducts;
var usingZoomer = false;
if(this.config.imageZoomer){
usingZoomer = true;
}
if(childProductId){
var price = childProducts[childProductId]["price"];
var finalPrice = childProducts[childProductId]["finalPrice"];
optionsPrice.productPrice = finalPrice;
optionsPrice.productOldPrice = price;
optionsPrice.reload();
optionsPrice.reloadPriceLabels(true);
optionsPrice.updateSpecialPriceDisplay(price, finalPrice);
if(this.config.updateShortDescription) {
this.updateProductShortDescription(childProductId);
}
if(this.config.updateDescription) {
this.updateProductDescription(childProductId);
}
if(this.config.updateProductName) {
this.updateProductName(childProductId);
}
if(this.config.customStockDisplay) {
this.updateProductAvailability(childProductId);
}
this.showTierPricingBlock(childProductId, this.config.productId);
if (usingZoomer) {
this.showFullImageDiv(childProductId, this.config.productId);
} else {
if(this.config.updateproductimage) {
this.updateProductImage(childProductId);
}
}
} else {
var cheapestPid = this.getProductIdOfCheapestProductInScope("finalPrice");
var price = childProducts[cheapestPid]["price"];
var finalPrice = childProducts[cheapestPid]["finalPrice"];
optionsPrice.productPrice = finalPrice;
optionsPrice.productOldPrice = price;
optionsPrice.reload();
optionsPrice.reloadPriceLabels(false);
if(this.config.updateProductName) {
this.updateProductName(false);
}
if(this.config.updateShortDescription) {
this.updateProductShortDescription(false);
}
if(this.config.updateDescription) {
this.updateProductDescription(false);
}
if(this.config.customStockDisplay) {
this.updateProductAvailability(false);
}
optionsPrice.updateSpecialPriceDisplay(price, finalPrice);
this.showTierPricingBlock(false);
this.showCustomOptionsBlock(false, false);
if (usingZoomer) {
this.showFullImageDiv(false, false);
} else {
if(this.config.updateproductimage) {
this.updateProductImage(false);
}
}
}
};
Product.Config.prototype.updateProductImage = function(productId) {
var imageUrl = this.config.imageUrl;
if(productId && this.config.childProducts[productId].imageUrl) {
imageUrl = this.config.childProducts[productId].imageUrl;
}
if (!imageUrl) {
return;
}
if($('image')) {
$('image').src = imageUrl;
} else {
$$('#product_addtocart_form p.product-image img').each(function(el) {
var dims = el.getDimensions();
el.src = imageUrl;
el.width = dims.width;
el.height = dims.height;
});
}
};
Product.Config.prototype.updateProductName = function(productId) {
var productName = this.config.productName;
if (productId && this.config.ProductNames[productId].ProductName) {
productName = this.config.ProductNames[productId].ProductName;
}
$$('#product_addtocart_form div.product-name h1').each(function(el) {
el.innerHTML = productName;
});
var productSku = this.config.sku ;
if (productId && this.config.childProducts[productId].sku) {
productSku = this.config.childProducts[productId].sku ;
}
jQuery('.sku span').text(productSku) ;
var productDelivery = this.config.delivery;
if (productId && this.config.childProducts[productId].delivery) {
productDelivery = this.config.childProducts[productId].delivery ;
}
jQuery('.delivery-info').html(productDelivery) ;
var productReturns = this.config.returns;
if (productId && this.config.childProducts[productId].returns) {
productReturns = this.config.childProducts[productId].returns ;
}
jQuery('.returns-info').html(productReturns) ;
var productDownloads = this.config.downloads;
if (productId && this.config.childProducts[productId].downloads) {
productDownloads = this.config.childProducts[productId].downloads;
}
if (productDownloads) jQuery('.downloads-info').html(productDownloads) ;
else jQuery('.downloads-info').html('There are no downloads for this product') ;
var productAttribs = this.config.attributesTable;
if (productId && this.config.childProducts[productId].attributesTable) {
productAttribs = this.config.childProducts[productId].attributesTable ;
}
jQuery('.attribs-info').html(productAttribs) ;
decorateTable('product-attribute-specs-table') ;
if (productId && this.config.childProducts[productId].isNew) {
jQuery('.product-image .new-label').show() ;
} else {
jQuery('.product-image .new-label').hide() ;
}
if (productId && this.config.childProducts[productId].isOnSale) {
jQuery('.product-image .sale-label').show() ;
} else {
jQuery('.product-image .sale-label').hide() ;
}
if (productId) jQuery('input[name="pid"]').val(productId) ;
};
Product.Config.prototype.updateProductAvailability = function(productId) {
var stockInfo = this.config.stockInfo;
var is_in_stock = false;
var stockLabel = '';
if (productId && stockInfo[productId]["stockLabel"]) {
stockLabel = stockInfo[productId]["stockLabel"];
stockQty = stockInfo[productId]["stockQty"];
is_in_stock = stockInfo[productId]["is_in_stock"];
}
$$('#product_addtocart_form p.availability span').each(function(el) {
if(is_in_stock) {
$$('#product_addtocart_form p.availability').each(function(es) {
es.removeClassName('availability out-of-stock');
es.addClassName('availability in-stock');
});
el.innerHTML = /*stockQty + ' ' + */stockLabel;
} else {
$$('#product_addtocart_form p.availability').each(function(ef) {
ef.removeClassName('availability in-stock');
ef.addClassName('availability out-of-stock');
});
el.innerHTML = stockLabel;
}
});
};
Product.Config.prototype.updateProductShortDescription = function(productId) {
var shortDescription = this.config.shortDescription;
if (productId && this.config.shortDescriptions[productId].shortDescription) {
shortDescription = this.config.shortDescriptions[productId].shortDescription;
}
$$('#product_addtocart_form div.short-description div.std').each(function(el) {
el.innerHTML = shortDescription;
});
};
Product.Config.prototype.updateProductDescription = function(productId) {
var description = this.config.description;
if (productId && this.config.Descriptions[productId].Description) {
description = this.config.Descriptions[productId].Description;
}
$$('#product_tabs_description_tabbed_contents div.std').each(function(el) {
el.innerHTML = description;
});
};
Product.Config.prototype.updateProductAttributes = function(productId) {
var productAttributes = this.config.productAttributes;
if (productId && this.config.childProducts[productId].productAttributes) {
productAttributes = this.config.childProducts[productId].productAttributes;
}
//If config product doesn't already have an additional information section,
//it won't be shown for associated product either. It's too hard to work out
//where to place it given that different themes use very different html here
console.log(productAttributes) ;
$$('div.product-collateral div.attribs-info').each(function(el) {
el.innerHTML = productAttributes;
decorateTable('product-attribute-specs-table');
});
};
Product.Config.prototype.showCustomOptionsBlock = function(productId, parentId) {
var coUrl = this.config.ajaxBaseUrl + "co/?id=" + productId + '&pid=' + parentId;
var prodForm = $('product_addtocart_form');
if ($('SCPcustomOptionsDiv')==null) {
return;
}
Effect.Fade('SCPcustomOptionsDiv', { duration: 0.5, from: 1, to: 0.5 });
if(productId) {
//Uncomment the line below if you want an ajax loader to appear while any custom
//options are being loaded.
//$$('span.scp-please-wait').each(function(el) {el.show()});
//prodForm.getElements().each(function(el) {el.disable()});
new Ajax.Updater('SCPcustomOptionsDiv', coUrl, {
method: 'get',
evalScripts: true,
onComplete: function() {
$$('span.scp-please-wait').each(function(el) {el.hide()});
Effect.Fade('SCPcustomOptionsDiv', { duration: 0.5, from: 0.5, to: 1 });
//prodForm.getElements().each(function(el) {el.enable()});
}
});
} else {
$('SCPcustomOptionsDiv').innerHTML = '';
try{window.opConfig = new Product.Options([]);} catch(e){}
}
};
Product.OptionsPrice.prototype.reloadPriceLabels = function(productPriceIsKnown) {
var priceFromLabel = '';
var prodForm = $('product_addtocart_form');
if (!productPriceIsKnown && typeof spConfig != "undefined") {
priceFromLabel = spConfig.config.priceFromLabel;
}
var priceSpanId = 'configurable-price-from-' + this.productId;
var duplicatePriceSpanId = priceSpanId + this.duplicateIdSuffix;
if($(priceSpanId) && $(priceSpanId).select('span.configurable-price-from-label'))
$(priceSpanId).select('span.configurable-price-from-label').each(function(label) {
label.innerHTML = priceFromLabel;
});
if ($(duplicatePriceSpanId) && $(duplicatePriceSpanId).select('span.configurable-price-from-label')) {
$(duplicatePriceSpanId).select('span.configurable-price-from-label').each(function(label) {
label.innerHTML = priceFromLabel;
});
}
};
//SCP: Forces the 'next' element to have it's optionLabels reloaded too
Product.Config.prototype.configureElement = function(element) {
this.reloadOptionLabels(element);
if(element.value){
this.state[element.config.id] = element.value;
if(element.nextSetting){
element.nextSetting.disabled = false;
this.fillSelect(element.nextSetting);
this.reloadOptionLabels(element.nextSetting);
this.resetChildren(element.nextSetting);
}
}
else {
this.resetChildren(element);
}
this.reloadPrice();
};
//SCP: Changed logic to use absolute price ranges rather than price differentials
Product.Config.prototype.reloadOptionLabels = function(element){
var selectedPrice;
var childProducts = this.config.childProducts;
var stockInfo = this.config.stockInfo;
//Don't update elements that have a selected option
if(element.options[element.selectedIndex].config){
return;
}
for(var i=0;i<element.options.length;i++){
if(element.options[i].config){
var cheapestPid = this.getProductIdOfCheapestProductInScope("finalPrice", element.options[i].config.allowedProducts);
var mostExpensivePid = this.getProductIdOfMostExpensiveProductInScope("finalPrice", element.options[i].config.allowedProducts);
var cheapestFinalPrice = childProducts[cheapestPid]["finalPrice"];
var mostExpensiveFinalPrice = childProducts[mostExpensivePid]["finalPrice"];
var stock = '';
if(cheapestPid == mostExpensivePid ){
if(stockInfo[cheapestPid]["stockLabel"] != '') {
stock = '( ' +stockInfo[cheapestPid]["stockLabel"] + ' )';
}
}
if (this.config.showOutOfStock){
if(this.config.disable_out_of_stock_option ) {
if(!stockInfo[cheapestPid]["is_in_stock"] ) {
if(cheapestPid == mostExpensivePid ){
element.options[i].disabled=true;
var stock = '( ' +stockInfo[cheapestPid]["stockLabel"] + ' )';
}
}
}
}
var tierpricing = childProducts[mostExpensivePid]["tierpricing"];
element.options[i].text = this.getOptionLabel(element.options[i].config, cheapestFinalPrice, mostExpensiveFinalPrice, stock , tierpricing);
}
}
};
Product.Config.prototype.showTierPricingBlock = function(productId, parentId) {
var coUrl = this.config.ajaxBaseUrl + "co/?id=" + productId + '&pid=' + parentId;
var prodForm = $('product_addtocart_form');
if(productId) {
new Ajax.Updater('sppTierPricingDiv', coUrl, {
method: 'get',
evalScripts: true,
onComplete: function() {
$$('span.scp-please-wait').each(function(el) {el.hide()});
}
});
} else {
$('sppTierPricingDiv').innerHTML = '';
}
};
//SCP: Changed label formatting to show absolute price ranges rather than price differentials
Product.Config.prototype.getOptionLabel = function(option, lowPrice, highPrice, stock, tierpricing){
var str = option.label;
if(tierpricing > 0 && tierpricing < lowPrice) {
var tierpricinglowestprice = ': As low as (' + this.formatPrice(tierpricing,false) + ')';
} else {
var tierpricinglowestprice = '';
}
if (!this.config.showPriceRangesInOptions) {
return str;
}
if (!this.config.showOutOfStock){
stock = '';
}
lowPrices = this.getTaxPrices(lowPrice);
highPrices = this.getTaxPrices(highPrice);
if (this.config.hideprices) {
if (this.config.showOutOfStock){
return str + ' ' + stock + ' ';
} else {
return str;
}
}
var to = ' ' + this.config.rangeToLabel + ' ';
var separator = ': ( ';
if(lowPrice && highPrice){
if (this.config.showfromprice) {
this.config.priceFromLabel = this.config.priceFromLabel; //'From: ';
}
if (lowPrice != highPrice) {
if (this.taxConfig.showBothPrices) {
str+= separator + this.formatPrice(lowPrices[2], false) + ' (' + this.formatPrice(lowPrices[1], false) + ' ' + this.taxConfig.inclTaxTitle.replace('Tax','VAT') + ')';
str+= to + this.formatPrice(highPrices[2], false) + ' (' + this.formatPrice(highPrices[1], false) + ' ' + this.taxConfig.inclTaxTitle.replace('Tax','VAT') + ')';
str += " ) ";
} else {
str+= separator + this.formatPrice(lowPrices[0], false);
str+= to + this.formatPrice(highPrices[0], false);
str += " ) ";
}
} else {
if (this.taxConfig.showBothPrices) {
str+= separator + this.formatPrice(lowPrices[2], false) + ' (' + this.formatPrice(lowPrices[1], false) + ' ' + this.taxConfig.inclTaxTitle.replace('Tax','VAT') + ')';
str += " ) ";
str += stock;
str += tierpricinglowestprice;
} else {
if(tierpricing == 0 ) {
str+= separator + this.formatPrice(lowPrices[0], false);
str += " ) ";
}
str += tierpricinglowestprice;
str += ' ' + stock;
}
}
}
return str;
};
//SCP: Refactored price calculations into separate function
Product.Config.prototype.getTaxPrices = function(price) {
var price = parseFloat(price);
if (this.taxConfig.includeTax) {
var tax = price / (100 + this.taxConfig.defaultTax) * this.taxConfig.defaultTax;
var excl = price - tax;
var incl = excl*(1+(this.taxConfig.currentTax/100));
} else {
var tax = price * (this.taxConfig.currentTax / 100);
var excl = price;
var incl = excl + tax;
}
if (this.taxConfig.showIncludeTax || this.taxConfig.showBothPrices) {
price = incl;
} else {
price = excl;
}
return [price, incl, excl];
};
//SCP: Forces price labels to be updated on load
//so that first select shows ranges from the start
document.observe("dom:loaded", function() {
//Really only needs to be the first element that has configureElement set on it,
//rather than all.
if (typeof opConfig != "undefined") {
spConfig.reloadPrice();
}
$('product_addtocart_form').getElements().each(function(el) {
if(el.type == 'select-one') {
if(el.options && (el.options.length > 1)) {
el.options[0].selected = true;
spConfig.reloadOptionLabels(el);
}
}
});
});
Thank you
The version 1.5.11 is not compatible w/ Magento 1.9 according to the extension version on Magento connect. Please obtain the newest version of the extension and/or ask the creator to give you support. As far as I can see 1.9 support is support with 1.11.6, released 11th March 2015. The infos on their homepage and Magento connect are different - not good. On the homepage it says Works with Magento 1.9.0.X . tested 15 May 2014.
I am building an Ionic app which has a list that is split using 'item divider'
The problem i am having is that when I use the buttons I have in the app to change the list order etc the divider text is not changing.
The divider text items are generated within an Angular directive.
I feel as though the problem is that the directive is not being re-called when the button is clicked.
Below is the code for the list and the directive.
I have also created a codepen to play about with if that makes things any easier.
Here is the CODEPEN LINK
Notice that when you use the search bar then delete the word the list does update
HTML/Ionic markup for the list
<ion-list id="list">
<ion-item
auto-list-divider
auto-list-divider-value="{{item[dividerString]}}"
auto-list-divider-function="dividerFunction"
ng-click="setDataSetClick(item.marker)"
ng-href="#/tab/films/{{item.id}}"
ng-repeat="item in outputData | filter:search.string | orderBy:dividerString:true">
<!-- If Film data show title p -->
<h3 ng-if="item.marker=='film';">{{item.title}}</h3>
<!-- If Cinema data show title p -->
<h3 ng-if="item.marker=='cinema';">{{item.cinema}}</h3>
</ion-item>
</ion-list>
Angular Controller
.controller('ListCtrl', function($scope, $timeout, $ionicScrollDelegate, Films, Cinemas, FilterList, OrderList, DataSetString, $ionicActionSheet) {
'use strict';
var cachedFilmData = Films.all(),
cachedCinemaData = Cinemas.all(),
indexedFilms = [];
$scope.dividerFunction = function(key) {
return key;
};
$scope.search = {
string: ''
};
$scope.dividerString = "year";
$scope.outputData = cachedFilmData;
$scope.filterString = FilterList.getFilter();
$scope.orderString = OrderList.getOrder();
$scope.itemsToFilter = function() {
indexedFilms = [];
return $scope.outputData;
};
$scope.filterFilms = function(films) {
var uniqueFilm = indexedFilms.indexOf(films[$scope.dividerString]) === -1;
if (uniqueFilm) {
indexedFilms.push(films[$scope.dividerString]);
}
return uniqueFilm;
};
$scope.setDataSetClick = function(data) {
DataSetString.setString(data);
};
// When the filter by button is clicked
$scope.showFilterActionSheet = function() {
$ionicActionSheet.show({
buttons: [{
text: 'Film'
}, {
text: 'Cinema'
}],
titleText: 'Select A Filter',
cancelText: 'Cancel',
buttonClicked: function(index, obj) {
FilterList.setFilter(obj.text);
$scope.filterString = FilterList.getFilter();
if ($scope.filterString === "Cinema") {
$scope.outputData = cachedCinemaData;
$scope.dividerString = "opened";
DataSetString.setString('cinema');
} else {
$scope.outputData = cachedFilmData;
$scope.dividerString = "year";
DataSetString.setString('film');
}
// Reset the order string tex
$scope.orderString = "Date";
return true;
}
});
};
// When the order by button is clicked
$scope.showOrderActionSheet = function() {
var activeDataSet = DataSetString.getString();
var optOne, optTwo, optThree;
if (activeDataSet === "cinema") {
optOne = "Opened";
optTwo = "Closed";
optThree = "Highlights";
} else {
optOne = 'Date';
optTwo = 'Themes';
optThree = 'Highlights';
}
$ionicActionSheet.show({
buttons: [{
text: optOne
}, {
text: optTwo
}, {
text: optThree
}],
titleText: 'Select An Order',
cancelText: 'Cancel',
buttonClicked: function(index, obj) {
var orderText = obj.text,
divider;
if (activeDataSet === "cinema") {
if (orderText === "Opened") {
divider = "opened";
}
if (orderText === "Closed") {
divider = "closed";
}
if (orderText === "Highlights") {
divider = "highlight";
}
sortData(cachedCinemaData, divider);
} else {
if (orderText === "Date") {
divider = "year";
}
if (orderText === "Themes") {
divider = "theme";
}
if (orderText === "Highlights") {
divider = "highlight";
}
sortData(cachedFilmData, divider);
}
$scope.orderString = obj.text;
$ionicScrollDelegate.scrollTop(true);
return true;
}
});
};
function sortData(data, divider) {
$scope.outputData = [];
var newOutputData = [];
for (var i = 0; i < data.length; i += 1) {
if (data[i][divider] != 0) {
console.log(divider);
newOutputData.push(data[i]);
}
}
$scope.outputData = newOutputData;
$scope.dividerString = divider;
}
})
Angular Directive
.directive('autoListDivider', function($timeout) {
var lastDivideKey = "";
return {
link: function(scope, element, attrs) {
var key = attrs.autoListDividerValue,
doDivide;
doDivide = function() {
var divideFunction = scope.$apply(attrs.autoListDividerFunction),
divideKey = divideFunction(key);
if (divideKey !== lastDivideKey) {
element.prepend(
'<h2 class="item item-divider custom--item-divider"><span ng-bind="divideKey">' + divideKey + '</span></h2>'
)
}
lastDivideKey = divideKey;
};
$timeout(doDivide, 0);
}
};
})
I have a JavaScript file using speechSynthesis.
I keep having this error:
"Cannot read property 'attachEvent' of null" in line 129:
Here it is:
speech.bind = function(event, element, callback) {
**if (element.attachEvent) {**
element.attachEvent('on'+event, callback )
} else if (window.addEventListener) {
element.addEventListener(event, callback ,false);
};
};
I will put in here the role code in here so anyone can check the entire JavaScript:
var speech_def = speech_def || {
container: "#glb-materia"
,insert_before: true
,ico: "http://edg-1-1242075393.us-east-1.elb.amazonaws.com/speech/listen_icon.jpg"
,bt_txt: "OUÇA A REPORTAGEM"
,bt_stop: "PARAR!"
,source: ".materia-conteudo"
,ignore: [
".foto-legenda"
,".frase-materia"
,"script"
,"style"
,"#speech"
,".sub-header"
,".chamada-materia"
,".data-autor"
,".box-tags"
,".saibamais"
]
};
var speech = speech || {};
//Polyfill remove()
Element.prototype.remove = function() {
this.parentElement.removeChild(this);
};
NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
for (var i = 0, len = this.length; i < len; i++) {
if(this[i] && this[i].parentElement) {
this[i].parentElement.removeChild(this[i]);
}
}
};
//Polyfill innerText
if ( (!('innerText' in document.createElement('a'))) && ('getSelection' in window) ) {
HTMLElement.prototype.__defineGetter__("innerText", function() {
var selection = window.getSelection(),
ranges = [],
str;
for (var i = 0; i < selection.rangeCount; i++) {
ranges[i] = selection.getRangeAt(i);
}
selection.removeAllRanges();
selection.selectAllChildren(this);
str = selection.toString();
selection.removeAllRanges();
for (var i = 0; i < ranges.length; i++) {
selection.addRange(ranges[i]);
}
return str;
})
}
speech.iOS = /(iPad|iPhone|iPod)/g.test( navigator.userAgent );
speech.Android = /(Android)/g.test( navigator.userAgent );
speech.include = function() {
var bt = ""
bt += '<div id="speech" '
+'title="'+speech_def.bt_txt+'" '
+'style="'
+'display: none; '
+'margin: 5px; '
+'font-size: 12px; '
+'font-style: italic; '
+'color: #bbbbbb; '
+'cursor: pointer;"'
+'>';
bt += '<img style="width: 25px; height: 25px;" src="'+speech_def.ico+'"> ';
bt += '<i style="vertical-align: top; line-height: 28px;">'+speech_def.bt_txt+'</i>';
bt += '</div>';
var button = document.createElement("SPAN");
button.innerHTML = bt;
var box = document.querySelectorAll(speech_def.container)[0];
if (speech_def.insert_before) {
box.insertBefore(button,box.firstChild);
} else {
box.appendChild(button)
};
};
speech.stop = function() {
window.speechSynthesis.cancel();
}
speech.stop();
speech.content = function() {
var result = "";
var boxes = speech_def.source.split(",");
boxes.reverse();
for (var n = boxes.length - 1; n >= 0; n--) {
var doc = document.querySelector(boxes[n]);
if (doc) {
doc = doc.cloneNode(true);
for (var i = speech_def.ignore.length - 1; i >= 0; i--) {
var els = doc.querySelectorAll(speech_def.ignore[i]);
for (var j = els.length - 1; j >= 0; j--) {
els[j].remove();
};
};
result += "." + doc.innerText;
};
};
return result;
};
speech.start_speech = function() {
var content = speech.content();
// Note: some voices don't support altering params
if (!speech.Android) speech.msg.voice = speech.voices[0];
// msg.voiceURI = 'native';
speech.msg.volume = speech.iOS?1:1; // 0 to 1
speech.msg.rate = speech.iOS?0.6:1; // 0.1 to 10
speech.msg.pitch = speech.iOS?1:1; // 0 to 2
speech.msg.text = content;
speech.msg.lang = 'pt-BR';
speech.msg.onend = function(e) {
// console.log('Finished in ' + event.elapsedTime + ' seconds.');
};
window.speechSynthesis.speak(speech.msg);
};
speech.read = function(){}; //chrome problem
speech.bind = function(event, element, callback) {
if (element.attachEvent) {
element.attachEvent('on'+event, callback )
} else if (window.addEventListener) {
element.addEventListener(event, callback ,false);
};
};
speech.click = function(e){
event.stopPropagation()
if (window.event) window.event.cancelBubble = true;
var control = document.getElementById("speech");
var label;
if (window.speechSynthesis.speaking) {
label = speech_def.bt_txt;
speech.stop();
} else {
label = speech_def.bt_stop;
speech.start_speech();
};
control.querySelector("i").innerHTML = label;
}
speech.bind_button = function() {
var control = document.getElementById("speech");
speech.bind("click",control,speech.click);
};
speech.show_button = function() {
if (!speech.on_page) {
speech.on_page = true;
speech.include();
speech.bind_button();
};
var control = document.getElementById("speech");
control.style.display="inline-block";
};
speech.test_portuguese = function() {
speech.voices = [];
window.speechSynthesis.getVoices().forEach(function(voice) {
if (voice.lang == "pt-BR") {
speech.voices.push(voice);
};
});
if (speech.Android) {
var control = document.getElementById("speech");
var complement = (speech.voices.length > 0)?"*":"";
// control.querySelector("i").innerHTML = "OUÇA A REPORTAGEM"+complement;
return true;
} else {
return (speech.voices.length > 0);
};
};
speech.start = function() {
if ('speechSynthesis' in window) {
speech.msg = new SpeechSynthesisUtterance();
if (speech.test_portuguese()) {
speech.show_button();
} else {
window.speechSynthesis.onvoiceschanged = function() {
if (speech.test_portuguese()) {
speech.show_button();
};
};
};
speech.bind_button();
};
};
speech.start();
speech.bind("load",window,speech.start)
How can i solve this problem?
Thanks so much.
The problem is that element is null at that point.
Probably, because there is no element with id="speech", so control in null in this code:
speech.bind_button = function() {
var control = document.getElementById("speech");
speech.bind("click",control,speech.click);
};