I'm trying to build a simple p.o.s entry in lightswitch html. And my problem is the total amount is not calculating in the correct event. I'm new to all this javascript and lightswitch so please forgive my innocence.
I have inserted a breakpoint in my "updateTotal function" the problem I have clearly is that it calls the updateTotal function once I click the addsales detail(When there is no data yet). What needs to happen is that it should call the updateTotal after I selected a product.
What am I doing wrong?
Below is the code I wrote. Can anybody help me?
myapp.AddEditSalesHeader.created = function (screen) {
// Write code here.
//Set the default values of the following fields.
screen.SalesHeader.InvoiceNo = "(Auto Invoice #)";
var vTime = new Date();
screen.SalesHeader.InvoiceTime = vTime;
screen.SalesHeader.ModePmt = "CASH";
screen.SalesHeader.Shipment = "PICK-UP";
screen.SalesHeader.PerDiscount = 0;
screen.SalesHeader.TotalDiscount = 0;
screen.SalesHeader.NetAmount = 0;
screen.SalesHeader.AmountReturn = 0;
screen.SalesHeader.CashReceived = 0;
screen.SalesHeader.ChangeDue = 0;
screen.findContentItem("InvoiceNo").isReadOnly = true;
screen.findContentItem("InvoiceDate").isReadOnly = true;
screen.findContentItem("TotalAmount").isReadOnly = true;
screen.findContentItem("NetAmount").isReadOnly = true;
};
myapp.AddEditSalesHeader.PerDiscount_postRender = function (element, contentItem) {
//Compute TotalAmount & NetAmount when PerDiscount value is entered
contentItem.dataBind("value",
function (PerDiscount) {
var vADisc = contentItem.screen.SalesHeader.TotalAmount * (PerDiscount / 100);
contentItem.screen.SalesHeader.TotalDiscount = vADisc;
contentItem.screen.SalesHeader.NetAmount = contentItem.screen.SalesHeader.TotalAmount - vADisc;
});
};
myapp.AddEditSalesHeader.TotalAmount_postRender = function (element, contentItem) {
function updateTotal() {
var InvDetail = contentItem.screen.SalesDetails.data;
var AmtDetail = 0;
InvDetail.forEach(function (sales) {
if (isNaN(sales.Amount)) {
AmtDetail = 0;
}
else {
//Update the TotalAmount
AmtDetail = AmtDetail + sales.Amount;
}
})
//Display the TotalAmount
contentItem.screen.SalesHeader.TotalAmount = AmtDetail;
contentItem.screen.SalesHeader.NetAmount = contentItem.screen.SalesHeader.TotalAmount
- contentItem.screen.SalesHeader.TotalDiscount;
}
//Set up a databind on screen.SaleDetails.count
contentItem.dataBind("screen.SalesDetails.count", function () {
updateTotal();}
);
}
myapp.AddEditSalesHeader.TotalDiscount_postRender = function (element, contentItem) {
// Write code here.
//Compute PerDiscount & NetAmount when the TotalDiscount value is entered
contentItem.dataBind("value",
function (TotalDiscount) {
if (TotalDiscount > 0) {
contentItem.screen.SalesHeader.PerDiscount = (TotalDiscount / contentItem.screen.SalesHeader.TotalAmount) * 100;
contentItem.screen.SalesHeader.NetAmount = contentItem.screen.SalesHeader.TotalAmount - TotalDiscount;
}
else {
contentItem.screen.SalesHeader.PerDiscount = 0;
}
});
};
myapp.AddEditSalesHeader.InvTime_postRender = function (element, contentItem) {
// Write code here.
this.setInterval(
function () {
var currentTime = new Date();
$(element).text(currentTime.toLocaleTimeString());
},
1000
);
};
//function CallGetTotAmt(operation) {
// $.ajax({
// type: 'post',
// data: {},
// url: '../Web/GetTotAmount.ashx',
// success: operation.code(function AjaxSuccess(AjaxResult) {
// operation.complete(AjaxResult);
// })
// });
//}
myapp.AddEditSalesHeader.Details_postRender = function (element, contentItem) {
// Write code here.
//Hide the save command button
$("[data-ls-tap='tap:{data.shell.saveCommand.command}']").hide();
//Hide the discard command button
$("[data-ls-tap='tap:{data.shell.discardCommand.command}']").hide();
};
myapp.AddEditSalesHeader.Cancel_execute = function (screen) {
// Write code here.
msls.showMessageBox("Close transaction? Closing will cause any unsaved changes to be discarded.", {
title: "System Advisory",
buttons: msls.MessageBoxButtons.yesNo
})
.then(function (result) {
if (result === msls.MessageBoxResult.yes) {
myapp.cancelChanges();
}
});
};
myapp.AddEditSalesHeader.Save_execute = function (screen) {
// Write code here.
//Get the total data in SalesHeader
myapp.activeDataWorkspace.ApplicationData.SalesHeaders.includeTotalCount().execute().then(function (result) {
var varInvNo = AutoInvNo(result);
//Set InvoiceNo before saving
screen.SalesHeader.InvoiceNo = varInvNo;
var InvDetail = screen.SalesDetails.data;
var varStock = 0;
InvDetail.forEach(function (entity) {
//Update ProductFile StockOnHand that have products in SalesDetail
varStock = entity.ProductFile.StockOnHand - entity.Quantity;
entity.ProductFile.StockOnHand = varStock;
entity.ProductFile.TranCode = "O";
entity.InvoiceNo = varInvNo;
})
myapp.commitChanges().then(null, function fail(e) {
msls.showMessageBox(e.message, { title: e.title }).then(function () {
screen.SalesHeader.InvoiceNo = "(Auto Invoice #)";
throw e;
});
});
});
};
//Utility
function AutoInvNo(InvNo) {
var InvNumber = 1;
var Entities = InvNo.results;
//Count the total data in SalesHeader
Entities.forEach(function (entity) {
InvNumber = InvNumber + 1;
});
//Return InvNumber value
return InvNumber;
};
myapp.AddEditSalesHeader.Print_execute = function (screen) {
// Write code here.
var LoadingDiv = $("<div></div>");
var Loading = $("<h1> Loading Report...</h1>");
Loading.appendTo(LoadingDiv);
LoadingDiv.appendTo($(element));
// Get Report
var HTMLContent = $("<div></div>").html(
"<object width='650px' height='650px' data='../Reports/BranchSalesReport.rdlc'/>"
);
// Make report appear on top of the Loading message
HTMLContent.css({
"margin-top": "-50px"
});
HTMLContent.appendTo($(element));
}
this will solve you problem: alls I have done is add the time interval to the code at the bottom so it knows to check the total multiple times... the post render function is only called once usually so the function inside wasn't actually being called.
function updateTotal() {
var InvDetail = contentItem.screen.SalesDetails.data;
var AmtDetail = 0;
InvDetail.forEach(function (sales) {
if (isNaN(sales.Amount)) {
AmtDetail = 0;
}
else {
//Update the TotalAmount
AmtDetail = AmtDetail + sales.Amount;
}
})
//Display the TotalAmount
contentItem.screen.SalesHeader.TotalAmount = AmtDetail;
contentItem.screen.SalesHeader.NetAmount = contentItem.screen.SalesHeader.TotalAmount
- contentItem.screen.SalesHeader.TotalDiscount;
}
this.setInterval(
function () {
//Set up a databind on screen.SaleDetails.count
contentItem.dataBind("screen.SalesDetails.count", updateTotal);
},1000);
and the below code solves the NaN within the Amt Discount and Net Amount:
myapp.AddEditSalesHeader.TotalDiscount_postRender = function (element, contentItem) {
// Write code here.
//Compute PerDiscount & NetAmount when the TotalDiscount value is entered
contentItem.dataBind("value",
function () {
if (contentItem.value > 0) {
contentItem.screen.SalesHeader.PerDiscount = (contentItem.value / contentItem.screen.SalesHeader.TotalAmount) * 100;
contentItem.screen.SalesHeader.NetAmount = contentItem.screen.SalesHeader.TotalAmount - contentItem.value;
}
else {
contentItem.value = 0;
}
});
};
Related
I have a chrome extension (JS) that I am building and when the user clicks on a button in the popup, the extension updates the chrome.storage.local to reflect what is on the popup and (in theory) when that is complete, it would run three content scripts. Unfortunately, the content script seem to start before the information is set in the popup.js.
I have tried Timeouts and Promises, however with both, it still runs the next function before the "chrome.storage.local.set" (in the updateStorage() function) is executed. Is there a better method/something that I am missing?
popup.js
console.log("popup.js");
function doContent() {
console.log("content1");
//checkboxes = document.getElementsByTagName("input");
//checkCheckboxes(checkboxes);
chrome.tabs.executeScript(null, { file: "content_addNote.js" });
}
function checkCheckboxes(checkboxes, orderArray) {
//console.log("checkboxes");
//console.log(checkboxes);
console.log("orderArray");
console.log(orderArray);
console.log("for loop running");
var ii = 0;
for (var i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == "checkbox") {
if (checkboxes[i].checked === false) {
console.log(i, orderArray[i], "will be removed for the list");
//console.log(orderArray[i]);
orderArray.splice(ii, 1);
ii = ii - 1;
console.log(orderArray);
}
ii += 1;
//console.log(i, checkboxes[i].checked);
}
}
console.log("for loop ended");
console.log("Output from checkCheckboxes");
console.log(orderArray);
return orderArray;
}
function updateStorage() {
console.log("updateStorage");
var emailSelect = document.getElementById("SelEmailType");
var emailType = emailSelect.options[emailSelect.selectedIndex].id;
if (document.getElementById("itemInfo").innerHTML === "Placeholder") {
console.log("Error. Placeholder not found");
} else {
var storedLegal = chrome.storage.local.get("newStorage", function (items) {
var newArray = { ...items };
console.log(newArray);
var orderList = items.newStorage.src_items;
console.log("orderList", orderList);
//console.log("indexOf", orderList.indexOf("\n"));
var orderArray = orderList.split("\n");
var checkboxes = new Array();
checkboxes = document.getElementsByTagName("input");
updatedOrder = checkCheckboxes(checkboxes, orderArray);
console.log(updatedOrder);
arraString = updatedOrder.join("\n");
//console.log(arraString);
//alert(arraString);
newArray.newStorage.src_items = arraString;
newArray.newStorage.src_emailType = emailType;
console.log("start newArray");
console.log(newArray);
console.log("end newArray");
console.log(newArray.newStorage);
chrome.storage.local.clear();
chrome.storage.local.set({
newStorage: newArray.newStorage,
});
//chrome.runtime.sendMessage({ newStorage: newArray.newStorage });
console.log("stored");
//console.log(chrome.runtime.local.get({ newStorage }));
});
}
console.log("End storedLegal");
return;
}
function one_by_one(objects_array, iterator, callback) {
/* var x = 1;
var y = null; // To keep under proper scope
setTimeout(function () {
x = x * 3 + 2;
y = x / 2;
}, 500); */
var start_promise = objects_array.reduce(function (prom, object) {
return prom.then(function () {
//var y = null; // To keep under proper scope
/* setTimeout(function () {
x = x * 3 + 2;
y = x / 2;
}, 500);
x = 1;
y = null; */
return chrome.tabs.executeScript(null, { file: object }); //iterator(object);
});
}, Promise.resolve()); // initial
if (callback) {
start_promise.then(callback);
} else {
return start_promise;
}
}
/*
function processArray(arr, fn) {
return arr.reduce(
(p, v) => p.then((a) => fn(v).then((r) => a.concat([r]))),
Promise.resolve([])
);
} */
function doContent2() {
console.log("doContent2");
updateStorage();
fileFunctions = [
"content2.js",
"content_addShippingNote.js",
"content_addNote.js",
"disconnect.js",
];
var x = 1;
var y = null; // To keep under proper scope
console.log("fileFunctions ");
new Promise((resolve, reject) => {
// Promise #1
updateStorage();
console.log("Promise #1 ");
setTimeout(function () {
x = x * 3 + 2;
y = x / 2;
}, 1000);
resolve();
})
.then((result) => {
var storedLegal = chrome.storage.local.get("newStorage", function (
items
) {
if ((items = undefined)) {
console.log("item not found");
// To keep under proper scope
setTimeout(function () {
x = 1;
y = null;
x = x * 3 + 2;
y = x / 2;
}, 500);
}
//console.log(items);
});
// Promise #2
chrome.tabs.executeScript(null, { file: "content2.js" });
console.log("Promise #2 ");
return result;
})
.then((result) => {
// Promise #3
chrome.tabs.executeScript(null, { file: "content_addShippingNote.js" });
console.log("Promise #3 ");
return result;
})
.then((result) => {
// Promise #3
chrome.tabs.executeScript(null, { file: "content_addNote.js" });
console.log("Promise #4 ");
return result;
});
//processArray(fileFunctions, runScript).then(console.log);
//fileFunctions.forEach(runScript);
//one_by_one(fileFunctions, "", "");
/* var promised = new Promise(updateStorage).then((result, err) => {
console.log("YA");
fileFunctions.forEach(runScript);
}); */
document.getElementById("btnCreateEmail").addEventListener("click", null);
//fileFunctions.forEach(runScript);
/* chrome.tabs.executeScript(null, { file: "content2.js" }),
chrome.tabs.executeScript(null, { file: "content_addShippingNote.js" }),
chrome.tabs.executeScript(null, { file: "content_addNote.js" }),
chrome.tabs.executeScript(null, { file: "disconnect.js" }), */
}
function runScript(fileName, index) {
console.log(index, ": ", fileName);
chrome.tabs.executeScript(null, { file: fileName });
}
function clearStorage() {
chrome.tabs.executeScript(null, { file: "disconnect.js" });
alert("local cleared");
}
function orderToHTML(orderList) {
var orderArray = orderList.split("\n");
// Draw HTML table
var perrow = 2, // cells per row
html = "<table><tbody>";
// Loop through array and add table cells
for (var i = 0; i < orderArray.length; i++) {
html +=
"<tr><td><input type=" &
"checkbox" &
" " &
"id=" &
i &
"/></td><td>" &
orderArray[i] &
"</td></tr>";
var next = i + 1;
if (next % perrow == 0 && next != orderArray.length) {
html += "</tr><tr>";
}
}
html += "</tbody></table>";
// Attach HTML to container
return html;
}
function setWaitPeriod(time) {
var x = 1;
var y = null; // To keep under proper scope
setTimeout(function () {
x = x * 3 + 2;
y = x / 2;
}, time);
}
//window.onload = function () {
//console.log("window.onload");
chrome.runtime.sendMessage({ popupOpen: true });
var port = chrome.runtime.connect();
chrome.runtime.onMessage.addListener((msg, sender) => {
// First, validate the message's structure.
if (msg.from === "content" && msg.subject === "showPageAction") {
document.getElementById("container").innerHTML = msg.container;
document.getElementById("itemInfo").innerHTML = msg.itemInfo;
}
});
document.getElementById("btnCreateEmail").addEventListener("click", doContent2);
//document.getElementById("btnClear").addEventListener("click", clearStorage);
//});
I have some JavaScrip that is meant to check if there are any media tags selected or industry tags selected--this is so the portfolio items can be sorted and displayed accordingly in the browser.
What I have almost works 100%, but I can't figure out how to make it so that if only a media tag is selected or if only an industry tag is selected, the portfolio items should still be sorted accordingly. Currently, you have to select a media tag AND an industry tag, but I'd like users to be able to search using just a media tag OR just an industry tag.
Here is what I want to accomplish: If only a media tag is selected, then get all portfolio pieces that are associated with that media tag. If only an industry tag is selected, get all portfolio items that are associated with that industry tag. If a media tag AND industry tag are selected at the same time, get all portfolio items that are associated with BOTH.
Vanilla JS isn't my strong point so forgive me if this is a dumb question, but this has had me stumped for hours now.
No jQuery answers, please, as this whole page's functionality is built using JavaScript.
Here is the function:
var update = function () {
closeDrawer();
// update ui to reflect tag changes
// get our list of items to display
var itemsToDisplay = [];
var currentMediaTag = controlsContainer.querySelector('.media.selected');
var currentIndustryTag = controlsContainer.querySelector('.industry.selected');
if (currentMediaTag != "" && currentMediaTag != null) {
selectedMediaFilter = currentMediaTag.innerHTML;
}
if (currentIndustryTag != "" && currentIndustryTag != null) {
selectedIndustryFilter = currentIndustryTag.innerHTML;
}
if (selectedMediaFilter == "" && selectedIndustryFilter == "") {
itemsToDisplay = portfolioItems.filter(function (item) {
return item.preferred;
});
} else {
itemsToDisplay = portfolioItems.filter(function (item) {
var mediaTags = item.media_tags,
industryTags = item.industry_tags;
if(industryTags.indexOf(selectedIndustryFilter) < 0){
return false;
}
else if(mediaTags.indexOf(selectedMediaFilter) < 0){
return false;
}
else{
return true;
}
});
}
renderItems(itemsToDisplay);
}
Not entirely sure it's necessary but just in case, here is the complete JS file that handles the portfolio page:
(function ($) {
document.addEventListener("DOMContentLoaded", function (event) {
// for portfolio interaction
var portfolioGrid = (function () {
var gridSize = undefined,
parentContainer = document.querySelector('.portfolio-item-container');
containers = parentContainer.querySelectorAll('.view'),
drawer = parentContainer.querySelector('.drawer'),
bannerContainer = drawer.querySelector('.banner-container'),
thumbsContainer = drawer.querySelector('.thumbs-container'),
descriptionContainer = drawer.querySelector('.client-description'),
clientNameContainer = drawer.querySelector('.client-name'),
controlsContainer = document.querySelector('.portfolio-controls-container'),
selectedMediaFilter = "", selectedIndustryFilter = "";
var setGridSize = function () {
var windowSize = window.innerWidth,
previousGridSize = gridSize;
if (windowSize > 1800) {
gridSize = 5;
} else if (windowSize > 900) {
gridSize = 4;
} else if (windowSize > 600 && windowSize <= 900) {
gridSize = 3;
} else {
gridSize = 2;
}
if (previousGridSize != gridSize) {
closeDrawer();
}
};
var attachResize = function () {
window.onresize = function () {
setGridSize();
};
};
var getRowClicked = function (boxNumber) {
return Math.ceil(boxNumber / gridSize);
};
var getLeftSibling = function (row) {
var cI = row * gridSize;
return containers[cI >= containers.length ? containers.length - 1 : cI];
};
var openDrawer = function () {
drawer.className = 'drawer';
scrollToBanner();
};
var scrollToBanner = function () {
var mainContainer = document.querySelector('#main-container'),
mainBounding = mainContainer.getBoundingClientRect(),
scrollY = (drawer.offsetTop - mainBounding.bottom) - 10,
currentTop = document.body.getBoundingClientRect().top;
animate(document.body, "scrollTop", "", document.body.scrollTop, scrollY, 200, true);
};
var animate = function (elem, style, unit, from, to, time, prop) {
if (!elem) return;
var start = new Date().getTime(),
timer = setInterval(function () {
var step = Math.min(1, (new Date().getTime() - start) / time);
if (prop) {
elem[style] = (from + step * (to - from)) + unit;
} else {
elem.style[style] = (from + step * (to - from)) + unit;
}
if (step == 1) clearInterval(timer);
}, 25);
elem.style[style] = from + unit;
}
var closeDrawer = function () {
drawer.className = 'drawer hidden';
};
var cleanDrawer = function () {
bannerContainer.innerHTML = "";
clientNameContainer.innerHTML = "";
descriptionContainer.innerHTML = "";
thumbsContainer.innerHTML = "";
};
var resetThumbs = function () {
Array.prototype.forEach.call(thumbsContainer.querySelectorAll('.thumb'), function (t) {
t.className = "thumb";
});
};
var handleBannerItem = function (item) {
bannerContainer.innerHTML = "";
if (item.youtube) {
var videoContainer = document.createElement('div'),
iframe = document.createElement('iframe');
videoContainer.className = "videowrapper";
iframe.className = "youtube-video";
iframe.src = "https://youtube.com/embed/" + item.youtube;
videoContainer.appendChild(iframe);
bannerContainer.appendChild(videoContainer);
} else if (item.soundcloud) {
var iframe = document.createElement('iframe');
iframe.src = item.soundcloud;
iframe.className = "soundcloud-embed";
bannerContainer.appendChild(iframe);
} else if (item.banner) {
var bannerImage = document.createElement('img');
bannerImage.src = item.banner;
bannerContainer.appendChild(bannerImage);
}
};
var attachClick = function () {
Array.prototype.forEach.call(containers, function (n, i) {
n.querySelector('a.info').addEventListener('click', function (e) {
e.preventDefault();
});
n.addEventListener('click', function (e) {
var boxNumber = i + 1,
row = getRowClicked(boxNumber);
var containerIndex = row * gridSize;
if (containerIndex >= containers.length) {
// we're inserting drawer at the end
parentContainer.appendChild(drawer);
} else {
// we're inserting drawer in the middle somewhere
var leftSiblingNode = getLeftSibling(row);
leftSiblingNode.parentNode.insertBefore(drawer, leftSiblingNode);
}
// populate
cleanDrawer();
var mediaFilterSelected = document.querySelector('.media-tags .tag-container .selected');
var selectedFilters = "";
if (mediaFilterSelected != "" && mediaFilterSelected != null) {
selectedFilters = mediaFilterSelected.innerHTML;
}
var portfolioItemName = '';
var selectedID = this.getAttribute('data-portfolio-item-id');
var data = portfolioItems.filter(function (item) {
portfolioItemName = item.name;
return item.id === selectedID;
})[0];
clientNameContainer.innerHTML = data.name;
descriptionContainer.innerHTML = data.description;
var childItems = data.child_items;
//We will group the child items by media tag and target the unique instance from each group to get the right main banner
Array.prototype.groupBy = function (prop) {
return this.reduce(function (groups, item) {
var val = item[prop];
groups[val] = groups[val] || [];
groups[val].push(item);
return groups;
}, {});
}
var byTag = childItems.groupBy('media_tags');
if (childItems.length > 0) {
handleBannerItem(childItems[0]);
var byTagValues = Object.values(byTag);
byTagValues.forEach(function (tagValue) {
for (var t = 0; t < tagValue.length; t++) {
if (tagValue[t].media_tags == selectedFilters) {
handleBannerItem(tagValue[0]);
}
}
});
childItems.forEach(function (item, i) {
var img = document.createElement('img'),
container = document.createElement('div'),
label = document.createElement('p');
container.appendChild(img);
var mediaTags = item.media_tags;
container.className = "thumb";
label.className = "childLabelInactive thumbLbl";
thumbsContainer.appendChild(container);
if (selectedFilters.length > 0 && mediaTags.length > 0) {
for (var x = 0; x < mediaTags.length; x++) {
if (mediaTags[x] == selectedFilters) {
container.className = "thumb active";
label.className = "childLabel thumbLbl";
}
}
}
else {
container.className = i == 0 ? "thumb active" : "thumb";
}
img.src = item.thumb;
if (item.media_tags != 0 && item.media_tags != null) {
childMediaTags = item.media_tags;
childMediaTags.forEach(function (cMTag) {
varLabelTxt = document.createTextNode(cMTag);
container.appendChild(label);
label.appendChild(varLabelTxt);
});
}
img.addEventListener('click', function (e) {
scrollToBanner();
resetThumbs();
handleBannerItem(item);
container.className = "thumb active";
});
});
}
openDrawer();
});
});
};
var preloadImages = function () {
portfolioItems.forEach(function (item) {
var childItems = item.child_items;
childItems.forEach(function (child) {
(new Image()).src = child.banner;
(new Image()).src = child.thumb;
});
});
};
//////////////////////////////////// UPDATE FUNCTION /////////////////////////////////////
var update = function () {
closeDrawer();
// update ui to reflect tag changes
// get our list of items to display
var itemsToDisplay = [];
var currentMediaTag = controlsContainer.querySelector('.media.selected');
var currentIndustryTag = controlsContainer.querySelector('.industry.selected');
if (currentMediaTag != "" && currentMediaTag != null) {
selectedMediaFilter = currentMediaTag.innerHTML;
}
if (currentIndustryTag != "" && currentIndustryTag != null) {
selectedIndustryFilter = currentIndustryTag.innerHTML;
}
if (selectedMediaFilter == "" && selectedIndustryFilter == "") {
itemsToDisplay = portfolioItems.filter(function (item) {
return item.preferred;
});
} else {
itemsToDisplay = portfolioItems.filter(function (item) {
var mediaTags = item.media_tags,
industryTags = item.industry_tags;
if (industryTags.indexOf(selectedIndustryFilter) < 0) {
return false;
}
else if (mediaTags.indexOf(selectedMediaFilter) < 0) {
return false;
}
else {
return true;
}
});
}
renderItems(itemsToDisplay);
}
//////////////////////////////////// RENDERITEMS FUNCTION /////////////////////////////////////
var renderItems = function (items) {
var children = parentContainer.querySelectorAll('.view');
Array.prototype.forEach.call(children, function (child) {
// remove all event listeners then remove child
parentContainer.removeChild(child);
});
items.forEach(function (item) {
var container = document.createElement('div'),
thumb = document.createElement('img'),
mask = document.createElement('div'),
title = document.createElement('h6'),
excerpt = document.createElement('p'),
link = document.createElement('a');
container.className = "view view-tenth";
container.setAttribute('data-portfolio-item-id', item.id);
thumb.src = item.thumb;
mask.className = "mask";
title.innerHTML = item.name;
excerpt.innerHTML = item.excerpt;
link.href = "#";
link.className = "info";
link.innerHTML = "View Work";
container.appendChild(thumb);
container.appendChild(mask);
mask.appendChild(title);
mask.appendChild(excerpt);
mask.appendChild(link);
parentContainer.insertBefore(container, drawer);
});
containers = parentContainer.querySelectorAll('.view');
attachClick();
};
var filterHandler = function (linkNode, tagType) {
var prevSelection = document.querySelector("." + tagType + '.selected');
if (prevSelection != "" && prevSelection != null) {
prevSelection.className = tagType + ' tag';
}
linkNode.className = tagType + ' tag selected';
update();
};
var clearFilters = function (nodeList, filterType) {
Array.prototype.forEach.call(nodeList, function (node) {
node.className = filterType + " tag";
console.log("Clear filters function called");
});
}
var attachFilters = function () {
var mediaFilters = controlsContainer.querySelectorAll('.tag.media'),
industryFilters = controlsContainer.querySelectorAll('.tag.industry'),
filterToggle = controlsContainer.querySelectorAll('.filter-toggle');
// resets
controlsContainer.querySelector('.media-tags .reset')
.addEventListener('click',
function (e) {
e.preventDefault();
selectedMediaFilter = "";
clearFilters(controlsContainer.querySelectorAll('.media-tags a.tag'), "media");
update();
}
);
controlsContainer.querySelector('.industry-tags .reset')
.addEventListener('click',
function (e) {
e.preventDefault();
selectedIndustryFilter = "";
clearFilters(controlsContainer.querySelectorAll('.industry-tags a.tag'), "industry");
update();
}
);
Array.prototype.forEach.call(filterToggle, function (toggle) {
toggle.addEventListener('click', function (e) {
if (controlsContainer.className.indexOf('open') < 0) {
controlsContainer.className += ' open';
} else {
controlsContainer.className = controlsContainer.className.replace('open', '');
}
});
});
//Attaches a click event to each media tag "button"
Array.prototype.forEach.call(mediaFilters, function (filter) {
filter.addEventListener('click', function (e) {
e.preventDefault();
// var selectedMediaFilter = controlsContainer.querySelector('.media.selected');
//console.log("Media tag: " +this.innerHTML); *THIS WORKS*
filterHandler(this, "media");
});
});
Array.prototype.forEach.call(industryFilters, function (filter) {
filter.addEventListener('click', function (e) {
e.preventDefault();
// var selectedIndustryFilter = this.querySelector('.industry.selected');
// console.log("Industry tag: " +this.innerHTML); *THIS WORKS*
filterHandler(this, "industry");
});
});
};
return {
init: function () {
setGridSize();
attachResize();
attachClick();
preloadImages();
// portfolio page
if (controlsContainer) {
attachFilters();
}
}
};
})();
portfolioGrid.init();
});
}());
$ = jQuery.noConflict();
if(industryTags.indexOf(selectedIndustryFilter) < 0){
return false;
}
else if(mediaTags.indexOf(selectedMediaFilter) < 0){
return false;
}
That part is giving you headaches. Whenever no industry tag or media tag is selected this will exit the function.
Change to:
if(industryTags.indexOf(selectedIndustryFilter) < 0 && mediaTags.indexOf(selectedMediaFilter) < 0){
return false;
}
Now it will test if at least one tag is selected. If so then render items.
I made a change just to experiment with an idea, and this setup works:
if((selectedIndustryFilter !="" && industryTags.indexOf(selectedIndustryFilter) < 0) || (selectedMediaFilter !="" && mediaTags.indexOf(selectedMediaFilter) < 0)){
return false;
}
return true;
Not sure if it's the best solution ever but it seems to work and I'm not going to complain.
Honestly do not know whats happen, this was working this morning, have not changed a thing but now when i click my button to generate my images I get this error.
Can anyone tell me why and how to fix this please.
Error
test initMock test generate 1
TypeError: Cannot create property 'style' on string 'a'
at i._createCanvasElement (fabric.min.js:2)
at i._createLowerCanvas (fabric.min.js:2)
at i._initStatic (fabric.min.js:2)
at initialize (fabric.min.js:3)
at new i (fabric.min.js:1)
at b.$scope.uploadImage (controller.js:855)
at b.$scope.generate (controller.js:929)
at fn (eval at compile (angular.js:15500), <anonymous>:4:144)
at e (angular.js:27285)
at b.$eval (angular.js:18372)
my functions
$scope.uploadImage = function (where) {
var deferred = $q.defer();
if (where === 'upload') {
var f = document.getElementById('uploadCreative').files[0];
var r = new FileReader();
r.onload = function () {
var image = new Image();
image.src = r.result;
image.onload = function () {
$scope.resize(image.src).then(function (response) {
deferred.resolve(response);
console.log('hehe NO!');
console.log('hehe NO!');
}).catch(function (response) {
})
}
};
r.readAsDataURL(f);
}
if (where === 'local') {
function ax(a, callback) {
callback(localStorage.getItem(a));
}
var loadCanvas = new fabric.Canvas('a');
divHeight = $('.image-builder').height();
if ($scope.format === '1') {
Aratio = 0.67;
} else if ($scope.format === '2') {
Aratio = 0.56;
} else if ($scope.format === '3') {
divHeight = divHeight / 1.5;
Aratio = 2;
} else if ($scope.format === '4') {
Aratio = 0.67;
} else {
Aratio = 1
}
loadCanvas.setHeight(divHeight - 15);
loadCanvas.setWidth((divHeight - 15) * Aratio);
if (localStorage.getItem('backgroundImage') !== 'null') {
background = localStorage.getItem('backgroundImage');
var imgBc = new Image();
imgBc.onload = function () {
// this is syncronous
Iwidth = this.width;
Iheight = this.height;
var f_img = new fabric.Image(imgBc);
loadCanvas.setBackgroundImage(f_img, loadCanvas.renderAll.bind(loadCanvas), {
scaleY: loadCanvas.height / Iheight,
scaleX: loadCanvas.width / Iwidth
});
var test = ax('CC-canvas', function (response) {
loadCanvas.loadFromJSON(response, function () {
loadCanvas.renderAll();
$scope.resize(loadCanvas.toDataURL()).then(function (response) {
deferred.resolve(response);
}).catch(function (response) {
})
});
});
};
imgBc.src = background;
} else {
var test = ax('CC-canvas', function (response) {
loadCanvas.loadFromJSON(response, function () {
loadCanvas.renderAll();
$scope.resize(loadCanvas.toDataURL()).then(function (response) {
deferred.resolve(response);
}).catch(function (response) {
console.log(response);
})
});
});
}
}
return deferred.promise;
};
$scope.generate = function () {
$scope.generating = true;
$scope.generateBtn = 'Generating';
for (i = 0; i < $scope.gallery.length; i++) {
$scope.select[i] = '';
}
$scope.gallery = [];
$scope.checkPhoto = [];
console.log("test generate 1");
$scope.uploadImage($scope.creative).then(function (result) {
console.log("test generate 2");
$scope.generateCanvas(result, $scope.left, $scope.tops, $scope.wi, $scope.hi, $scope.per, $scope.btmR, $scope.btmL, $scope.backUrl)
.then(function () {
$timeout(function () {
//push final photo to array befor send to back end
$scope.photosToPhp.push(canvas2.toDataURL());
}, 800);
if ($scope.count < ($scope.photos[$scope.format].length - 1)) {
$scope.generate();
$scope.count++;
$scope.left = $scope.photos[$scope.format][$scope.count]['left'];
$scope.tops = $scope.photos[$scope.format][$scope.count]['tops'];
$scope.wi = $scope.photos[$scope.format][$scope.count]['wi'];
$scope.hi = $scope.photos[$scope.format][$scope.count]['hi'];
$scope.per = $scope.photos[$scope.format][$scope.count]['per'];
$scope.btmR = $scope.photos[$scope.format][$scope.count]['btmR'];
$scope.btmL = $scope.photos[$scope.format][$scope.count]['btmL'];
$scope.backUrl = "/mm3/public/img/formats/" + $scope.format + "/" + $scope.photos[$scope.format][$scope.count]['backUrl'];
$scope.$apply();
console.log("test generate 3");
} else {
//all photos've been pushed now sending it to back end
$timeout(function () {
// console.log($scope.photosToPhp[0]);
$http.post('/mm3/savePhoto', $scope.photosToPhp).then(function (success) {
$scope.generating = false;
$scope.generateBtn = 'Generate';
//creating mock up gallery
for (var x = 0; x < success.data.photos; x++) {
var file = '/mm3/tmp/' + success.data.folder + "/out" + x + ".png";
$scope.gallery.push(file);
}
$scope.photosToPhp = [];
}, function (error) {
});
}, 800);
$scope.count = 0;
$scope.left = $scope.photos[$scope.format][$scope.count]['left'];
$scope.tops = $scope.photos[$scope.format][$scope.count]['tops'];
$scope.wi = $scope.photos[$scope.format][$scope.count]['wi'];
$scope.hi = $scope.photos[$scope.format][$scope.count]['hi'];
$scope.per = $scope.photos[$scope.format][$scope.count]['per'];
$scope.btmR = $scope.photos[$scope.format][$scope.count]['btmR'];
$scope.btmL = $scope.photos[$scope.format][$scope.count]['btmL'];
$scope.backUrl = "/mm3/public/img/formats/" + $scope.format + "/" + $scope.photos[$scope.format][$scope.count]['backUrl'];
$scope.$apply();
}
console.log("test generate 4");
})
.catch(function (errorUrl) {
console.log(errorUrl);
})
})
};
Solved bu downgrading fabric js to 1.5 not 1.7 that i upgraded to, dont know why this worked but it dose
I am using the tubeplayer plugin to generate video playlists for my hot 100 music chart website http://beta.billboard.fm.
I pull playlist data and generate video playlists based on that data. The problem is that I currently am manually entering the youtube video ID for initial video load video on the home page, where I would like to create a variable that dynamically pulls the first youtube video id and inserts after initialVideo
So I am trying to create a variable that pulls track #1 from the hot 100 year playlist that I can place in the standard plugin parameters:
I will define it as var initialVideoID =
<script>
// IE workaround
function JSONQuery(url, callback) {
if ($.browser.msie && window.XDomainRequest) {
// alert('ie');
// var url = "http://gdata.youtube.com/feeds/api/videos?q=cher&category=Music&alt=json";
// Use Microsoft XDR
var xdr = new XDomainRequest();
xdr.open("get", url);
xdr.onerror = function () {
console.log('we have an error!');
}
xdr.onprogress = function () {
// console.log('this sucks!');
};
xdr.ontimeout = function () {
console.log('it timed out!');
};
xdr.onopen = function () {
console.log('we open the xdomainrequest');
};
xdr.onload = function () {
// XDomainRequest doesn't provide responseXml, so if you need it:
var dom = new ActiveXObject("Microsoft.XMLDOM");
dom.async = true;
dom.loadXML(xdr.responseText);
// alert(xdr.responseText);
callback(jQuery.parseJSON(xdr.responseText));
// alert(data.feed.entry[0].media$group.media$content[0].url);
// alert("ie");
};
xdr.send();
} else {
$.getJSON(url, callback);
}
};
var yearMap = [];
createYearMap();
function createYearMap() {
yearMap["1940"] = [1946, 1947, 1948, 1949];
yearMap["2010"] = [2010, 2011, 2012];
for (var i = 195; i < 201; i++) {
var curDecade = i * 10;
yearMap[curDecade.toString()] = [];
for (var j = 0; j < 10; j++) {
yearMap[curDecade][j] = curDecade + j;
}
}
}
// console.log(yearMap["2010"]);
(function ($) {
$(window).ready(function () {
// alert("before get");
// $.get("test.htm", function(data) {
// // var fileDom = $(data);
// // alert("get callback");
// $("#jqueryTest").html(data);
// });
// setInterval(function(){alert("Hello")},3000);
$(".song-description").mCustomScrollbar();
// var url = "http://ws.audioscrobbler.com/2.0/?method=track.getInfo&api_key=26178ccca6d355d31b413f3d54be5332&artist=" +"pink floyd" + "&track=" + "money" + "&format=json";
// JSONQuery(url, function(data) {
// if (data.track) {
// if (data.track.wiki) {
// $("#song-info").html(data.track.wiki.summary);
// } else {
// $("#song-info").html("No song info found");
// }
// } else {
// $("#song-info").html("No song info found");
// console.log("artist not found");
// }
// $(".song-description").mCustomScrollbar("update");
// });
// $("#example tbody tr").click(function() {
// selectPlaying(this, true);
// });
jQuery(".youtube-video").tubeplayer({
width: 300, // the width of the player
height: 225, // the height of the player
allowFullScreen: "true", // true by default, allow user to go full screen
initialVideo: var initialvideoID, // the video that is loaded into the player
preferredQuality: "default", // preferred quality: default, small, medium, large, hd720
showinfo: true, // if you want the player to include details about the video
modestbranding: true, // specify to include/exclude the YouTube watermark
wmode: "opaque", // note: transparent maintains z-index, but disables GPU acceleratio
theme: "dark", // possible options: "dark" or "light"
color: "red", // possible options: "red" or "white"
onPlayerEnded: function () {
videoEnded();
},
onPlayerPlaying: function (id) {
setIconToPause();
}, // after the play method is called
onPlayerPaused: function () {
setIconToPlay();
}, // after the pause method is called
onStop: function () {}, // after the player is stopped
onSeek: function (time) {}, // after the video has been seeked to a defined point
onMute: function () {}, // after the player is muted
onUnMute: function () {} // after the player is unmuted
});
setInterval(function () {
updateProgressBar()
}, 1000);
loadPlaylist("hot100", true);
});
})(jQuery);
var initialvideoID = "yyDUC1LUXSU"
function videoEnded() {
nextVideo();
}
var intervalTimer;
function startPlayer() {
jQuery(".youtube-video").tubeplayer("play");
playing = true;
clearInterval(intervalTimer);
intervalTimer = setInterval(function () {
updateProgressBar()
}, 1000);
setIconToPause();
}
function setIconToPause() {
var button = $(".icon-play");
if (button) {
button.removeClass("icon-play")
button.addClass("icon-pause");
}
}
function setIconToPlay() {
var button = $(".icon-pause");
if (button) {
button.removeClass("icon-pause")
button.addClass("icon-play");
}
}
function pausePlayer() {
jQuery(".youtube-video").tubeplayer("pause");
playing = false;
clearInterval(intervalTimer);
setIconToPlay();
}
function selectPlaying(item, autoStart) {
var nowPlayingItem = $(".nowPlaying");
if (nowPlayingItem) {
nowPlayingItem.removeClass("nowPlaying");
}
$(item).addClass("nowPlaying");
var aPos = $('#example').dataTable().fnGetPosition(item);
var aData = $('#example').dataTable().fnGetData(aPos);
if (aData[3]) {
// $("#song-info").html("Loading song info...");
$("#song-info").html("");
var url = "http://ws.audioscrobbler.com/2.0/?method=track.getInfo&api_key=26178ccca6d355d31b413f3d54be5332&artist=" + aData[1] + "&track=" + aData[2] + "&format=json";
JSONQuery(url, function (data) {
if (data.track) {
if (data.track.wiki) {
$("#song-info").html(data.track.wiki.summary);
} else {
$("#song-info").html("No song info found");
}
} else {
$("#song-info").html("No song info found");
console.log("artist not found");
}
// $(".song-description").mCustomScrollbar("update");
});
$(".info-rank").html("#" + aData[0]);
$(".info-artist").html(aData[1]);
$(".info-song").html(aData[2]);
$(".info-year").html($("#navYear").html());
var ytId = aData[3];
if (autoStart) {
jQuery(".youtube-video").tubeplayer("play", ytId);
setIconToPause();
} else {
jQuery(".youtube-video").tubeplayer("cue", ytId);
setIconToPlay();
}
clearInterval(intervalTimer);
intervalTimer = setInterval(function () {
updateProgressBar()
}, 1000);
playing = true;
// alert("youtube video id is: " + ytId);
} else {
alert("no youtube id");
}
}
function previousVideo() {
var curPlaying = $(".nowPlaying")[0];
var nextItem;
if (curPlaying) {
nextItem = $('#example').dataTable().fnGetAdjacentTr(curPlaying, false);
if (!nextItem) {
nextItem = $('#example').dataTable().fnGetNodes($('#example').dataTable().fnSettings().fnRecordsTotal() - 1);
}
} else {
nextItem = $('#example').dataTable().fnGetNodes(0);
}
selectPlaying(nextItem, true);
}
function nextVideo() {
var curPlaying = $(".nowPlaying")[0];
var nextItem;
if (curPlaying) {
nextItem = $('#example').dataTable().fnGetAdjacentTr(curPlaying, true);
if (!nextItem) {
nextItem = $('#example').dataTable().fnGetNodes(0);
}
} else {
nextItem = $('#example').dataTable().fnGetNodes(0);
}
selectPlaying(nextItem, true);
}
function updateProgressBar() {
// console.log("update bar");
myData = jQuery(".youtube-video").tubeplayer("data");
// console.log("update progress bar: " + (myData.currentTime / myData.duration * 100) + "%");
$(".bar").width((myData.currentTime / myData.duration * 100) + "%");
}
var playing = false;
function playPauseClick() {
if (playing) {
pausePlayer();
} else {
startPlayer();
}
}
function loadPlaylist(year) {
loadPlaylist(year, false);
}
function loadPlaylist(year, cueVideo) {
$.get("playlist/" + year + "playlist.txt", function (data) {
// var fileDom = $(data);
// alert("get callback");
// $("#playlistContents").html(data);
// $('#example').dataTable().fnAddData(data);
// var obj = eval("[[1,2,3],[1,2,3]]");
// obj = eval(data.toString());
obj = $.parseJSON(data);
// console.log(obj);
$('#example').dataTable().fnClearTable();
$('#example').dataTable().fnAddData(obj);
// $("#example tbody tr").click(function() {
// selectPlaying(this, true);
// });
if (year == "hot100") {
$("#navYear").html("Weekly Hot 100");
$("#navYearLabel").hide();
} else {
$("#navYear").html(year);
$("#navYearLabel").show();
}
if (cueVideo) {
selectPlaying($('#example').dataTable().fnGetNodes(0), false);
}
// $('#example').dataTable().fnAddData(data);
});
}
function modalDecadeClick(decade) {
var string = "";
if (decade == 'hot100') {
loadPlaylist("hot100");
$('#modal-example-decade').modal('hide');
$('#modal-year').modal('hide');
} else {
for (var i = 0; i < yearMap[decade].length; i++) {
string += '<li>' + yearMap[decade][i] + '</li>';
}
$('#modal-example-decade').modal('hide');
$('#specific-year-list').empty();
$('#specific-year-list').html(string).contents();
}
}
function modalYearClick(node) {
var year = parseInt($(node).children("li").html());
// console.log($(node).children("li").html());
$('#modal-year').modal('hide');
loadPlaylist(year);
}
function progressBarClick(e) {
var seekPercent = (e.pageX - $(".progress:first").offset().left) / $(".progress:first").width();
var seekTime = jQuery(".youtube-video").tubeplayer("data").duration * seekPercent;
jQuery(".youtube-video").tubeplayer("seek", seekTime);
}
var minYear = 1946;
var maxYear = 2012;
function nextYear() {
var year = $("#navYear").html();
if (year == "Weekly Hot 100") {
alert("Max year is " + maxYear);
return;
}
year = parseInt($("#navYear").html());
year++;
if (year > maxYear) {
loadPlaylist("hot100");
return;
}
loadPlaylist(year);
}
function prevYear() {
var year = $("#navYear").html();
if (year == "Weekly Hot 100") {
loadPlaylist(2012);
return;
}
year = parseInt($("#navYear").html());
year--;
if (year < minYear) {
alert("Min year is " + minYear);
return;
}
loadPlaylist(year);
}
function closeFilter() {
toggle_visibility('toggle-filter');
var oTable = $('#example').dataTable();
// Sometime later - filter...
oTable.fnFilter('');
}
</script>
I'm having trouble with designing a class which exposes its actions through callbacks. Yes my approach works for me but also seems too complex.
To illustrate the problem I've drawn the following picture. I hope it is useful for you to understand the class/model.
In my approach, I use some arrays holding user defined callback functions.
....
rocket.prototype.on = function(eventName, userFunction) {
this.callbacks[eventName].push(userFunction);
}
rocket.prototype.beforeLunch = function(){
userFunctions = this.callbacks['beforeLunch']
for(var i in userFunctions)
userFunctions[i](); // calling the user function
}
rocket.prototype.lunch = function() {
this.beforeLunch();
...
}
....
var myRocket = new Rocket();
myRocket.on('beforeLunch', function() {
// do some work
console.log('the newspaper guys are taking pictures of the rocket');
});
myRocket.on('beforeLunch', function() {
// do some work
console.log('some engineers are making last checks ');
});
I'm wondering what the most used approach is. I guess I could use promises or other libraries to make this implementation more understandable. In this slide using callbacks is considered evil. http://www.slideshare.net/TrevorBurnham/sane-async-patterns
So, should I use a library such as promise or continue and enhance my approach?
var Rocket = function () {
this.timer = null;
this.velocity = 200;
this.heightMoon = 5000;
this.goingToMoon = true;
this.rocketStatus = {
velocity: null,
height: 0,
status: null
};
this.listener = {
};
}
Rocket.prototype.report = function () {
for (var i in this.rocketStatus) {
console.log(this.rocketStatus[i]);
};
};
Rocket.prototype.on = function (name,cb) {
if (this.listener[name]){
this.listener[name].push(cb);
}else{
this.listener[name] = new Array(cb);
}
};
Rocket.prototype.initListener = function (name) {
if (this.listener[name]) {
for (var i = 0; i < this.listener[name].length; i++) {
this.listener[name][i]();
}
return true;
}else{
return false;
};
}
Rocket.prototype.launch = function () {
this.initListener("beforeLaunch");
this.rocketStatus.status = "Launching";
this.move();
this.initListener("afterLaunch");
}
Rocket.prototype.move = function () {
var that = this;
that.initListener("beforeMove");
if (that.goingToMoon) {
that.rocketStatus.height += that.velocity;
}else{
that.rocketStatus.height -= that.velocity;
};
that.rocketStatus.velocity = that.velocity;
if (that.velocity != 0) {
that.rocketStatus.status = "moving";
}else{
that.rocketStatus.status = "not moving";
};
if (that.velocity >= 600){
that.crash();
return;
}
if (that.rocketStatus.height == 2000 && that.goingToMoon)
that.leaveModules();
if (that.rocketStatus.height == that.heightMoon)
that.landToMoon();
if (that.rocketStatus.height == 0 && !that.goingToMoon){
that.landToEarth();
return;
}
that.report();
that.initListener("afterMove");
that.timer = setTimeout(function () {
that.move();
},1000)
}
Rocket.prototype.stop = function () {
clearTimeout(this.timer);
this.initListener("beforeStop");
this.velocity = 0;
this.rocketStatus.status = "Stopped";
console.log(this.rocketStatus.status)
this.initListener("afterStop");
return true;
}
Rocket.prototype.crash = function () {
this.initListener("beforeCrash");
this.rocketStatus.status = "Crashed!";
this.report();
this.stop();
this.initListener("afterCrash");
}
Rocket.prototype.leaveModules = function () {
this.initListener("beforeModules");
this.rocketStatus.status = "Leaving Modules";
this.initListener("afterModules");
}
Rocket.prototype.landToMoon = function () {
this.initListener("beforeLandToMoon");
this.rocketStatus.status = "Landing to Moon";
this.goingToMoon = false;
this.initListener("afterLandToMoon");
}
Rocket.prototype.landToEarth = function () {
this.initListener("beforeLandToEarth");
this.stop();
this.rocketStatus.status = "Landing to Earth";
this.initListener("afterLandToEarth");
}
Rocket.prototype.relaunch = function () {
this.initListener("beforeRelaunch");
this.timer = null;
this.velocity = 200;
this.heightMoon = 5000;
this.goingToMoon = true;
this.rocketStatus = {
velocity: 200,
height: 0,
status: "relaunch"
};
this.launch();
this.initListener("afterRelaunch");
}
init;
var rocket = new Rocket();
rocket.on("afterLaunch", function () {console.log("launch1")})
rocket.on("afterLandToMoon", function () {console.log("land1")})
rocket.on("beforeLandToEarth", function () {console.log("land2")})
rocket.on("afterMove", function () {console.log("move1")})
rocket.on("beforeLaunch", function () {console.log("launch2")})
rocket.launch();
You can add any function before or after any event.
This is my solution for this kinda problem. I am not using any special methods anything. I was just wonder is there any good practise for this like problems. I dig some promise,deferred but i just can't able to to this. Any ideas ?