@bva/recommendations
Advanced tools
Comparing version 0.0.3 to 0.0.4
{ | ||
"name": "@bva/recommendations", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"description": "JS recommendations widget using Shopify native recommendations API", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -33,4 +33,4 @@ Recommendations | ||
}; | ||
const recommendation = new Recommendations(options); | ||
recommendation.initialize(); | ||
const recs = new Recommendations(options); | ||
recs.initialize(); | ||
``` | ||
@@ -46,8 +46,8 @@ | ||
<script> | ||
var options = { | ||
var config = { | ||
productId: 10590155084, | ||
limit: 6 | ||
}; | ||
var recommendation = new Shopify.Recommendations(options); | ||
recommendation.initialize(); | ||
var recs = new Shopify.Recommendations(config); | ||
recs.initialize(); | ||
</script> | ||
@@ -58,4 +58,7 @@ ``` | ||
## Options | ||
## Configuration Object | ||
A configuration is required when initializing your Recommendations instance and uses the following properties: | ||
- **productId** - The ID of the product recommendations will be based off of | ||
- **hiddenTag** - (default: `"recommendations::hide"`) Tag that hides specific products | ||
@@ -66,2 +69,53 @@ - **insertion** - (default: `"[data-recommendations-insertion]"`) HTML element that the reviews will be inserted into | ||
## Product Id | ||
The Product ID is what will be used in the request to Shopify to figure out which products to display. It must be passed to your instance upon instantiation via 1 of the following methods. | ||
### HTML (Recommended Method) | ||
Add the data attribute `data-recommendations-main-product-id` to your insertion element and add the product id as a value to that. This is the recommended method because you'll usually have access to the Product ID via liquid. It is much easier for a future developer to read this and understand what's happening. | ||
```html | ||
<div data-recommendations-insertion data-recommendations-main-product-id="1234567890"></div> | ||
``` | ||
In Liquid | ||
```html | ||
<div data-recommendations-insertion data-recommendations-main-product-id="{{ product.id }}"></div> | ||
``` | ||
### JS | ||
Pass the `productId` value along with your configuration object. | ||
```javascript | ||
const config = { | ||
productId: 1234567890, | ||
limit: 5, | ||
}; | ||
const recs = Shopify.Recommendations(config); | ||
recs.initialize(); | ||
``` | ||
In Liquid | ||
```html | ||
<script> | ||
Shopify.customVariables = { | ||
productId: {{ product.id }} | ||
}; | ||
</script> | ||
``` | ||
```javascript | ||
const config = { | ||
productId: window.Shopify.customVariables.productId, | ||
limit: 5, | ||
}; | ||
... | ||
``` | ||
## Template | ||
@@ -99,4 +153,27 @@ | ||
## Methods | ||
### initialize | ||
Initializes a Recommendations instance and adds it to the page. | ||
```javascript | ||
const recs = Shopify.Recommendations({ variantId: 1234567890 }); | ||
recs.initialize(); | ||
``` | ||
### reinitialize | ||
*Needs documentation* | ||
### uninitialize | ||
*Needs documentation* | ||
### updateOptions | ||
*Needs documentation* | ||
## Events | ||
- `recommendations.initialized`: Fires when a recommendation instance is initialized. The callback you will find the product data in `event.detail.data` and the current instance in `event.detail.context`. |
@@ -8,7 +8,9 @@ import setupHtmlString from './_setup-html-string'; | ||
if (!insertion) { | ||
throw `Insertion element does not exist - ${context.options.insertion}`; | ||
throw new Error(`Insertion element does not exist - ${context.options.insertion}`); | ||
} | ||
insertion.innerHTML = html; | ||
insertion.setAttribute('data-recommendations-id', context.recommendationsId); | ||
return true; | ||
}; |
@@ -1,8 +0,13 @@ | ||
export default (options) => { | ||
if (!options) { | ||
throw 'Recommendations requires configuration object' | ||
export default (config) => { | ||
if (!config) { | ||
return false; | ||
} | ||
if (!options.productId) { | ||
throw 'Recommendations object requires a product ID'; | ||
if (config.limit && typeof config.limit !== 'number') { | ||
throw new Error('Recommendations: property `limit` needs to be of type Number'); | ||
} | ||
if (config.limit && config.limit > 10) { | ||
throw new Error('Recommendations: property `limit` requires value less than 10'); | ||
} | ||
}; |
@@ -13,2 +13,5 @@ import convertCentsToDollars from './helpers/convert-cents-to-dollars'; | ||
export default (data, context) => { | ||
if (!data.products) { | ||
throw new Error(`No products found for product ID: ${context.options.productId}`); | ||
} | ||
return data.products.map((product) => { | ||
@@ -15,0 +18,0 @@ if (product.tags.includes(context.options.hiddenTag)) { |
102
src/index.js
@@ -13,2 +13,3 @@ /** | ||
import defaultOptions from './_default-options'; | ||
import getProductIdFromInsertion from './_get-product-id-from-insertion'; | ||
@@ -22,14 +23,47 @@ /** | ||
class Recommendations { | ||
constructor(options) { | ||
checkIfOptionsAreValid(options); | ||
constructor(config) { | ||
checkIfOptionsAreValid(config); | ||
let productId; | ||
if (config && config.productId) { | ||
productId = config.productId; | ||
} else { | ||
if (config && config.insertion) { | ||
productId = getProductIdFromInsertion(config.insertion); | ||
} else { | ||
productId = getProductIdFromInsertion(defaultOptions.insertion); | ||
} | ||
} | ||
if (!productId) { | ||
throw new Error( | ||
'`Product ID was not provided by config object nor insertion element' | ||
); | ||
} | ||
this.productId = productId; | ||
const updatedOptions = {}; | ||
_.assign(updatedOptions, defaultOptions, options); | ||
_.assign(updatedOptions, defaultOptions); | ||
if (config) { | ||
_.assign(updatedOptions, config); | ||
} | ||
this.options = updatedOptions; | ||
this.isInitialized = false; | ||
this.recommendationsId = Math.floor(100000000 + Math.random() * 900000000); | ||
} | ||
/** | ||
* Gets the data, sets up JS connections and renders the recs to the screen | ||
* | ||
* @async | ||
* @function initialize | ||
*/ | ||
initialize() { | ||
const url = `/recommendations/products.json?product_id=${this.options.productId}&limit=${this.options.limit}`; | ||
const url = `/recommendations/products.json?product_id=${this.productId}&limit=${this.options.limit}`; | ||
const context = this; | ||
// TODO: if data has already been stored and product id is the same, do not run another fetch | ||
fetch(url) | ||
@@ -54,4 +88,64 @@ .then((response) => { | ||
}); | ||
this.isInitialized = true; | ||
}) | ||
.catch((err) => { | ||
throw err; | ||
}); | ||
} | ||
/** | ||
* Updates the configuration object | ||
* | ||
* @function updateOptions | ||
* @param {Object} updates | ||
*/ | ||
updateOptions(config) { | ||
_.assign(this.options, config); | ||
} | ||
/** | ||
* Uninitiallizes the recs instance then initializes it with the current options | ||
* | ||
* @function reinitialize | ||
*/ | ||
reinitialize() { | ||
if (!this.isInitialized) { | ||
throw new Error('Cannot reinitialize Recommendations object (has not been initialized)'); | ||
} | ||
this.uninitialize(); | ||
this.initialize(); | ||
} | ||
/** | ||
* Removes recs instance from the page but keeps it availabe to be initialized again | ||
* | ||
* @function uninitialize | ||
*/ | ||
uninitialize(preventEvent) { | ||
if (!this.isInitialized) { | ||
throw new Error('Cannot unitialize Recommendations object (has not been initialized)'); | ||
} | ||
this.isInitialized = false; | ||
const parents = document.querySelectorAll(`[data-recommendations-id="${this.recommendationsId}"]`); | ||
if (!parent) { | ||
throw new Error(`Cannot uninitiale Recommendations object (cannot find insertion with ID ${this.recommendationsId})`); | ||
} | ||
parents.forEach((parent) => { | ||
while (parent.firstChild) { | ||
parent.firstChild.remove(); | ||
} | ||
}); | ||
if (!preventEvent) { | ||
dispatchEvent('recommendations.uninitialized', { | ||
context: this, | ||
data: this.data, | ||
}); | ||
} | ||
} | ||
} | ||
@@ -58,0 +152,0 @@ |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
285928
17
557
175