--- 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.) [[toc]] ## Basic scripts Let's see how to create a component with scripts using Blocks. ```js 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: ```html
``` 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: ```html
``` 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: ```js 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 ```js 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: ```html
``` There is actually a solution to make your scripts behave dynamically, you can interpolate properties of the component model. ```js editor.BlockManager.add('test-block', { ... content: { myModelPropName: 'John', script: function () { alert('Hi {[ myModelPropName ]}'); console.log('the element', this); }, ... } }); ``` The final HTML will be: ```html
``` You can even change tags used for the interpolation ```js var editor = grapesjs.init({ ... // Default values tagVarStart: '{[ ', tagVarEnd: ' ]}', ... }); ``` You can use this technique with [property Traits](https://github.com/artf/grapesjs/wiki/Traits#add-traits-to-components) 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. ```js ... 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: ```js 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 * [grapesjs-navbar](https://github.com/artf/grapesjs-navbar) * [grapesjs-component-countdown](https://github.com/artf/grapesjs-component-countdown)