6.2 KiB
| title |
|---|
| Components & JS |
Components & JS
In this guide you'll see how to attach component related scripts and deal with external javascript libraries (for stuff like counters, galleries, slideshows, etc.)
Basic scripts
Let's see how to create a component with scripts using Blocks.
editor.BlockManager.add('test-block', {
label: 'Test block',
attributes: {class: 'fa fa-text'},
content: {
script: "alert('Hi'); console.log('the element', this)",
// Add some style just to make the component visible
style: {
width: '100px',
height: '100px',
'background-color': 'red',
}
}
});
Now if you drag the new block inside the canvas you'll see an alert popup and the message in console, as you might expected.
One thing worth noting is that this context is binded to the component element, so, for example, if you want to change some property you'd do this.innerHTML = 'inner content'.
One thing you should take in account is how the script is binded to component once rendered in the canvas or in your final template. If you check now the generated HTML coded by the editor (via Export button or editor.getHtml()), you might see something like this:
<div id="c764"></div>
<script>
var items = document.querySelectorAll('#c764');
for (var i = 0, len = items.length; i < len; i++) {
(function(){
// START component code
alert('Hi');
console.log('the element', this)
// END component code
}.bind(items[i]))();
}
</script>
As you see the editor attaches a unique ID to all components with scripts and retrieves them via querySelectorAll. Dragging another test-block will generate this:
<div id="c764"></div>
<div id="c765"></div>
<script>
var items = document.querySelectorAll('#c764, #c765');
for (var i = 0, len = items.length; i < len; i++) {
(function(){
// START component code
alert('Hi');
console.log('the element', this)
// END component code
}.bind(items[i]))();
}
</script>
Keep in mind that all component scripts are executed only inside the iframe of the canvas (isolated, just like your final template), therefore are NOT part of the current document and all your external libraries (eg. JQuery) are not there, but you'll see further how to manage scripted components with dependencies.
One thing you might be concerned about is a string used for the script, definitely not the best way to deal with a code, for this reason GrapesJS is able also to handle functions for you, so the previous example might look like this:
editor.BlockManager.add('test-block', {
...
content: {
script: function () {
alert('Hi');
console.log('the element', this);
},
...
}
});
Much easier now, but be aware of a string conversion, you can't use variables outside of the function scope, let's see this scenario
var myVar = 'John';
editor.BlockManager.add('test-block', {
...
script: function () {
alert('Hi ' + myVar);
console.log('the element', this);
},
...
});
Unfortunately, this won't work as you'll get undefined myVar error. The final HTML, with script functions converted to string, will look like this:
<div id="c764"></div>
<script>
var items = document.querySelectorAll('#c764');
for (var i = 0, len = items.length; i < len; i++) {
(function(){
// START component code
alert('Hi ' + myVar); // <- ERROR: undefined myVar
console.log('the element', this);
// END component code
}.bind(items[i]))();
}
</script>
There is actually a solution to make your scripts behave dynamically, you can interpolate properties of the component model.
editor.BlockManager.add('test-block', {
...
content: {
myModelPropName: 'John',
script: function () {
alert('Hi {[ myModelPropName ]}');
console.log('the element', this);
},
...
}
});
The final HTML will be:
<div id="c764"></div>
<script>
var items = document.querySelectorAll('#c764');
for (var i = 0, len = items.length; i < len; i++) {
(function(){
alert('Hi John');
console.log('the element', this);
}.bind(items[i]))();
}
</script>
You can even change tags used for the interpolation
var editor = grapesjs.init({
...
// Default values
tagVarStart: '{[ ',
tagVarEnd: ' ]}',
...
});
You can use this technique with property Traits to create highly customizable components.
Dependencies
As we mentioned above, scripts are executed independently inside the iframe of the canvas, where you won't find any dependency, so exactly as the final HTML generated by the editor. If you want to make use of external libraries you have basically 2 types of approaches, component related and template related.
Component related
If you're building, for example, a slider component based on some third-party library you probably would like to include the external file only when the component is actually dragged inside the canvas, in this case, component related approaches is the perfect one as it's loading external libraries dynamically. All you have to do is to require the dependency when is needed and then call your script.
...
script: function () {
var el = this;
var initMySLider = function() {
CoolSliderJS.init(el);
}
if (typeof CoolSliderJS == 'undefined') {
var script = document.createElement('script');
script.onload = initMySLider;
script.src = 'https://.../coolslider.min.js';
document.body.appendChild(script);
}
},
...
Template related
Some dependency might be highly used along all your components (eg. JQuery) so instead requiring it inside each script you might want to inject it directly inside the canvas:
var editor = grapesjs.init({
...
canvas: {
scripts: ['https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js']
}
});
...
script: function () {
// Do stuff using jquery
$('...');
},
...
Examples
Examples of components using scripts inside