Startup widgets contain logic to add
Third-party apps use startup widgets to capture events and perform tasks on those events.
StoreHippo uses Single Page Architecture so startup widgets are executed only once. Once loaded, when a user switches pages, then widgets are not executed. If you want to write code for the specific page then you need to handle that through page events.
Go to Site > Startup Widgets section in StoreHippo Admin Panel to manage startup scripts.
To add a new startup widget, click on Add New button in the top right corner.
Enter the name of the startup script.
Provide your startup javascript code in this field. You can use global objects in the controller code.
Provide the HTML code. You can use global widgets in the template code.
StoreHippo triggers various events in different actions on your store. You can use these events and bind a handler to these events.
(eventName, callback)
Use this global function to bind to a particular event. The callback function is invoked when the event is triggered. The event object is passed to the callback function as the only argument.
ms.bind('ms.page_change_start', function(event) {
// code here
});
(eventName, data)
It is used to trigger an event. data is the object containing the data that need to pass to the event handlers.
There are standard events that are triggered in default theme automatically:
ms.trigger("ms.page_change_start");
The event object is the standard Event Interface used by all Javascript DOM events. In addition, it contains a data property that contains the data that was passed while triggering the event.
data | Data passed at the time of triggering of the event. |
ms.page_change_start | Triggered when page change is started. call event.stopPropagation to prevent it to happen. The event.data.to contains the target page URL and event.data.from contains the current page URL. |
ms.page_change_success | Triggered when page change is successful and page rendering has just started. You can use ms.page object to get information about the page. |
ms.page_loaded | Triggered when page is loaded. Page is considered fully loaded when a) there is no ajax requests pending b) main resource data is loaded (e.g. product data on product page) c) ajax requests are still pending after 5000ms (default timeout). |
ms.page_not_found | Triggered when a page is not found. |
ms.message | Triggered automatically whenever API response contains messages. It can be triggered manually to display messages to customers. |
ms.order_placed | Triggered when the order is successfully placed. Event data has orders array that might contain a single order (in case of single seller) or multiple orders (in case of multiple sellers) |
ms.cart_loaded | Triggered when user cart is loaded and is available for use. You can then use ms.cart global object to interact with the cart. |
ms.cart_updated | Triggered everytime cart is updated e.g. when item is added to cart or user address is updated or coupon is applied. You can then use ms.cart global object to access the updated cart and perform your business logic. |
ms.cart_item_added | Triggered when an item is added to the cart. |
ms.cart_item_removed | Triggered when an item is removed from the cart. |
ms.user_login | Triggered when user log in successfully. You can use ms.user global object to get details of the logged in user. example |
ms.user_register | Triggered when user registers successfully. example |
ms.user_logout | Triggered when user logs out. |
ms.user_verified | Triggered when user successfully verifies through a link |
ms.mobile_app_initialized | In case of mobile app, this event is triggered when mobile app is initialized. |
ms.bind("ms.page_change_start", function (event) {
if (event.data && event.data.to && event.data.to.indexOf("/page/test") > -1) {
event.preventDefault();
}
});
ms.bind("ms.page_loaded", function (event) {
if (ms.page.name == "checkout") {
ms.loadScripts("<url to external script>").then(function() {
console.log("Script loaded");
});
}
});
ms.bind("ms.page_loaded", function (event) {
if (ms.page.name == 'product') {
console.log(ms.product);
}
});
ms.bind('ms.page_loaded', function(event) {
// Direct user to login page if a user is not logged in.
if(!ms.user.isLoggedIn){
ms.goTo('/user/login')
}
});
ms.loadScripts("<url to external script>").then(function() {
// Write code to be executed after the script is loaded
});
ms.bind('ms.order_placed', function(event) {
/* In case of single seller, orders will have a single order
In case of multiple sellers, orders will have multiple orders. In addition, it will have originalOrder property that you can use to access the original order before splitting */
event.data.orders.forEach(function(order) {
console.log("ORDER", order);
});
});
ms.bind("ms.wishlist_added", function (event) {
var product = event.data;
console.log('added product in wishlist', product)
});
ms.bind("ms.wishlist_removed", function (event) {
var productId = event.data;
ms.app.get({'entity':"ms.products" , 'recordId': productId } , function(err, res){
var product = res.data
console.log('removed product from wishlist', product)
})
});
ms.bind("ms.coupon_applied", function () {
var coupon = ms.cart.coupon_code;
console.log('added coupon in cart', coupon)
});
ms.bind("ms.user_updated", function () {
console.log('updated user', ms.user)
});
StoreHipp provides the REST API. You can call the StoreHippo API in frontend theme using ms.api.
Example: To list products
ms.app.call({command : "list", entity : "ms.products"}, function(err, response){
if(err){
// handle error
} else {
console.log("Response ", response);
}
})
Besides events, you can also use frontend API hooks to intercept the request and response of API hooks.
Example: Restrict user to enter at least 5 items of any product
ms.app.addPrehook({entity: 'ms.carts', command: 'addItem'}, function(req, res, next) {
if(ms.cart.item.quantity < 5) {
// show a message to your user alert('There must be at least 5 items in the cart');
return res.send(406);
} return next();
});
Example: Validate order options before placing order.
ms.app.addPrehook({entity: 'ms.carts', command: 'addItem'}, function(req, res, next) {
if(!ms.cart.options.test || ms.cart.options.test.length < 5) { alert("The value for test must be longer than 5 characters"); return res.send(406); } return next();
});
Example: Calculate the total weight of the cart items
ms.app.addPosthook({entity: 'ms.carts', command: 'addItem'}, function(req, res, next) {
if(res.data && res.data.cart) {
res.data.cart.total_weight = 0;
res.data.cart.items.forEach(function(item) {
res.data.cart.total_weight += item.weight;
});
}
next();
});
Example:
ms.app.addPosthook({entity: "ms.carts", command: "addItem"}, function (req, res, next) {
var addedItem = res.data.product;
window._izq.push(["event","Buy Now",{
"Category":addedItem.product.categories[0],
"Product Name":addedItem.name,
"Price":addedItem.price,
"Quantity":addedItem.quantity
}]);
next();
});
Example: Custom code when a user is logged out
ms.app.addPosthook({entity: "ms.users", command: "logout"}, function (req, res, next) {
//put your custom code here or call your API
next();
});
Example: Autopopulate country in shipping form as per substore metafield
ms.app.addPosthook({entity: "ms.forms", command: "list"}, function(req, res, next) {
var form = (res.data && res.data.data && res.data.data[0]) || (res.data && res.data[0]);
if(ms.substore && ms.substore.metafields && ms.substore.metafields.country){
if(form.name == 'shipping_address'){
form.fields.forEach(function(field){
if(field.name == 'country'){
field.settings.default = ms.substore.metafields.country;
}
})
}
}
return next();
});
Example: Custom code to show alert on form Submission.
ms.app.addPosthook({entity: 'ms.forms', command: 'performActions'}, function(req, res, next) {
alert('Form successfully submitted')
next();
})
Example: Custom code to show and hide data Substore specific
<div ng-if="ms.substore.alias == 'china'">
Privacy Policy for China
</div>
<div ng-if="ms.substore.alias == 'india'">
Privacy Policy for India
</div>
Example: GTM Add
ms.app.addPosthook({entity: "ms.carts", command: "addItem"}, function (req, res, next) {
var product = res.data.product;
window.dataLayer.push({
'event': 'addToCart',
'ecommerce': {
'currencyCode': ms.user.currency.name,
'add': {
'products': [
{
'name': product.name,
'id': product._id,
'price': product.price,
'brand': product.brand,
'category': product.categories,
'variant': product.variant_id,
'quantity': product.quantity
}
]
}
}
});
next();
});
Example: Fetch data from external API
ms.app.addPrehook({entity: "ms.products", command: "list"}, function (req, res, next) { fetch("https://externalapi.com/products").then(function(response) {
res.send(response);
}); });
NOTE: The next() call need to be there to pass control to the next code in line.