Table of Contents |
---|
Purpose
Cubbles allows the users to provide an html node to be observed for mutations and then dispatch an event when a mutation occurs. The observed mutations are the ones which corresponds to {childList: true}
. For further information about Mutations please check this documentation.
The RTE contains an utility called mutation-based-cubx-startevent
which contains the following attibutes:
- data-cubx-target-selector: To provide a css selector to indicate which node should be observed
- data-cubx-emit-event: To indicate the name of the event, which should be dispatched when a mutation occurs.
Info |
---|
It is important to highlight that the only mutation to be observed is the first one that occurs, after that the event will be dispatched and the observer will be disconnected. |
The following sections present a demo to indicate the proper use of the mutation-based-cubx-startevent
utility.
Demo
Prerequisites
- A component called
test-texarea
is available within the store you are currently working - The
test-texarea
has the following interface:
Sample case
Let's say say you are building an app where a Cubbles component will be included. The component will be append to a div container, but you need the Cubbles RTE to start working after this div suffers a mutation. Thus, you need to use the mutation-based-cubx-startevent.
Using iframe mutation-based-cubx-startevent utility
To use the mutation-based-cubx-startevent
first we need to:
- included ut as script within the head of our html components.
- Additionally, as usual, we should include the
webcomponents-lite
and thecrc-loader
scripts. - Furthermore, since we want the Cubbles RTE to start working after a mutation occurs, we need to provide a value for the
data-cubx-startevent
within thecrc-loader
script
Lets say we want to observe a div, whose id is observable. And we want the name of the event to be dispatched to be mutationBasedStart. Therefore, the values of the mutation-based-cubx-startevent
attributes should be:
Attribute | Value |
---|---|
data-cubx-target-selector | #observable |
data-cubx-emit-event | mutationBasedStart |
The head element
Using the information presented above the head element of our app should look similar to the one shown below:
Code Block | ||||
---|---|---|---|---|
| ||||
<head> <meta charset="UTF-8"> <title>Mutation based start event demo</title> <link rel="stylesheet" type="text/css" href="style.css"> <script src="../../cubx.core.rte@2.3.0-SNAPSHOT/webcomponents-lite/webcomponents-lite.js"></script> <script src="../../cubx.core.rte@2.3.0-SNAPSHOT/mutation-based-cubx-startevent/js/mutationBasedCubxStartevent.js" data-cubx-target-selector="#observable" data-cubx-emit-event="mutationBasedStart"></script> <script src="../../cubx.core.rte@2.3.0-SNAPSHOT/crc-loader/js/main.js" data-cubx-startevent="mutationBasedStart" data-crcinit-loadcif="true"></script> </head> |
We have additionally include a title for the app and a style sheet which will be use later.
The body element
As you can already imagine, the body of our app should have a div container with an id equals to 'observable'. That will be enough, however we want our app to explain how our mutation-based-cubx-startevent
works, so we will also include the following elements:
- A title for our app
- A description of the values of the {{mutation-based-cubx-startevent}} attributes
- A description of the utility works in this particular case
- A button to append the component called
test-textarea
- And a loader to be shown while the Cubbles RTE is working
The code of the body of our app should now look as follows:
Code Block | ||||
---|---|---|---|---|
| ||||
<h1>Mutation based start event demo</h1> <h2>Attribute values</h2> <p>The attributes have following values:</p> <ul> <li><strong>data-cubx-mutation-target-node:</strong> "#observable"</li> <li><strong>data-cubx-emit-event:</strong> "mutationBasedStart"</li> </ul> <h2>How it works</h2> <p> Every change on the element with the id 'observable' will be detected, thus appending an element will cause the 'mutationBasedStart' to be dispatched. </p> <p> Now you can <strong>click on</strong> the button below to cause the mutation to see it working: </p> <button id="appendComp">Append 'test-textarea'</button> <hr> <div class="loader"></div> <div id="observable"></div> |
A script to control behavior
We need a script to be able to:
- Create and init the
test-textarea
component using the /wiki/spaces/RTE/pages/19304335. - Append the
test-textarea
component to the observable div after the appendComp button is clicked. - Show the loader while the Cubbles RTE is working
- Hide the loader and show the observable when the component is ready
Our code should look similar to the one shown below:
Code Block | ||||
---|---|---|---|---|
| ||||
<script> (function () { 'use strict'; var loader = document.querySelector('.loader'); var appendComp = document.querySelector('#appendComp'); var observable = document.querySelector('#observable'); // Append the test-textarea component to the observable div after the appendComp button is clicked. appendComp.addEventListener('click', function () { observable.appendChild(createTextareaComponent()); appendComp.setAttribute('disabled', 'disabled'); loader.style.display = 'block'; }); // Hide the loader and show the observable when the component is ready document.addEventListener('cifReady', function () { loader.style.display = 'none'; observable.style.display = 'block'; }); // Function to Create the test-textarea component using the The Cubbles Tag API. function createTextareaComponent() { var init = document.createElement('cubx-core-init'); init.style.display = 'none'; init.appendChild(createSlotInit('label', '"Textarea label"')); init.appendChild(createSlotInit('cols', '40')); init.appendChild(createSlotInit('rows', '8')); var testTextarea = document.createElement('test-textarea'); testTextarea.setAttribute('cubx-webpackage-id', 'this'); testTextarea.appendChild(init); return testTextarea; } // Function to create a cubx-core-slot-init using the The Cubbles Tag API. function createSlotInit(slotName, slotValue) { var slotInit = document.createElement('cubx-core-slot-init'); slotInit.setAttribute('slot', slotName); slotInit.innerHTML = slotValue; return slotInit; } })() </script> |
Note |
---|
Note that here we assume that the |
The style
Now we need to style the loader div, so that it looks like spinner and let the user know that the component is loading, i.e. the Cubbles RTE is working on getting the component ready. Additionally, we want the observable div to be hidden by default.The style should look as follows:
Code Block | ||
---|---|---|
| ||
.loader { border: 8px solid #f3f3f3; border-radius: 50%; border-top: 8px solid #3498db; width: 30px; height: 30px; -webkit-animation: spin 2s linear infinite; animation: spin 2s linear infinite; display: none; } @-webkit-keyframes spin { 0% { -webkit-transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } #observable{ display: none; } |
Result
Working app
Iframe | ||||||
---|---|---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Mutation based start event demo</title> <link rel="stylesheet" type="text/css" href="style.css"> <script src="../../cubx.core.rte@2.3.0-SNAPSHOT/webcomponents-lite/webcomponents-lite.js"></script> <script src="../../cubx.core.rte@2.3.0-SNAPSHOT/mutation-based-cubx-startevent/js/mutationBasedCubxStartevent.js" data-cubx-target-selector="#observable" data-cubx-emit-event="mutationBasedStart"></script> <script src="../../cubx.core.rte@2.3.0-SNAPSHOT/crc-loader/js/main.js" data-cubx-startevent="mutationBasedStart" data-crcinit-loadcif="true"></script> </head> <body> <h1>Mutation based start event demo</h1> <h2>Attribute values</h2> <p>The attributes have following values:</p> <ul> <li><strong>data-cubx-mutation-target-node:</strong> "#observable"</li> <li><strong>data-cubx-emit-event:</strong> "mutationBasedStart"</li> </ul> <h2>How it works</h2> <p> Every change on the element with the id 'observable' will be detected, thus appending an element will cause the 'mutationBasedStart' to be dispatched. </p> <p> Now you can <strong>click on</strong> the button below to cause the mutation to see it working: </p> <button id="appendComp">Append 'test-textarea'</button> <hr> <div class="loader"></div> <div id="observable"></div> <script> (function () { 'use strict'; var loader = document.querySelector('.loader'); var appendComp = document.querySelector('#appendComp'); var observable = document.querySelector('#observable'); appendComp.addEventListener('click', function () { observable.appendChild(createTextareaComponent()); appendComp.setAttribute('disabled', 'disabled'); loader.style.display = 'block'; }); document.addEventListener('cifReady', function () { loader.style.display = 'none'; observable.style.display = 'block'; }); function createTextareaComponent() { var init = document.createElement('cubx-core-init'); init.style.display = 'none'; init.appendChild(createSlotInit('label', '"Textarea label"')); init.appendChild(createSlotInit('value', '"Value of textarea"')); init.appendChild(createSlotInit('cols', '40')); init.appendChild(createSlotInit('rows', '8')); var testTextarea = document.createElement('test-textarea'); testTextarea.setAttribute('cubx-webpackage-id', 'this'); testTextarea.appendChild(init); return testTextarea; } function createSlotInit(slotName, slotValue) { var slotInit = document.createElement('cubx-core-slot-init'); slotInit.setAttribute('slot', slotName); slotInit.innerHTML = slotValue; return slotInit; } })() </script> </body> </html> |
Target node added dynamically
Sometimes you would like to be available to add our target node dynamically, in this case the utility mutation-based-cubx-startevent
will wait until the node is added to the body to observe it for changes. Below a working example is presented:
A working example
Iframe | ||||||
---|---|---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Mutation based start event demo</title> <link rel="stylesheet" type="text/css" href="style.css"> <script src="../../cubx.core.rte@2.3.0-SNAPSHOT/webcomponents-lite/webcomponents-lite.js"></script> <script src="../../cubx.core.rte@2.3.0-SNAPSHOT/mutation-based-cubx-startevent/js/mutationBasedCubxStartevent.js" data-cubx-target-selector="#observable" data-cubx-emit-event="mutationBasedStart"></script> <script src="../../cubx.core.rte@2.3.0-SNAPSHOT/crc-loader/js/main.js" data-cubx-startevent="mutationBasedStart" data-crcinit-loadcif="true"></script> </head> <body> <a href="index.html">Go back</a> <h1>Mutation based start event demo</h1> <h2>Attribute values</h2> <p>The attributes have following values:</p> <ul> <li><strong>data-cubx-mutation-target-node:</strong> "#observable"</li> <li><strong>data-cubx-emit-event:</strong> "mutationBasedStart"</li> </ul> <h2>How it works</h2> <p> After the target node, in this case an element with the id 'observable', is added; every change on the target node will be detected, thus adding an element within the target node will cause the 'mutationBasedStart' to be dispatched. </p> <p> Now you can perform the following steps to see it working: </p> <ol> <li> First, the target node should be added: <div><button id="appendTargetNode">Append target node</button></div> </li> <li> Then, a component should be added to the target node, so that the rte starts working: <div><button id="appendComp" disabled>Append 'test-textarea'</button></div> </li> </ol> <hr> <div class="loader"></div> <script> (function () { 'use strict'; var loader = document.querySelector('.loader'); var appendCompBtn = document.querySelector('#appendComp'); var appendTargetNodeBtn = document.querySelector('#appendTargetNode'); var targetNode = document.createElement('div'); targetNode.setAttribute('id', 'observable'); appendTargetNodeBtn.addEventListener('click', function () { document.body.appendChild(targetNode); appendTargetNodeBtn.setAttribute('disabled', 'disabled'); appendCompBtn.removeAttribute('disabled'); }); appendCompBtn.addEventListener('click', function () { targetNode.appendChild(createTextareaComponent()); appendCompBtn.setAttribute('disabled', 'disabled'); loader.style.display = 'block'; }); document.addEventListener('cifReady', function () { loader.style.display = 'none'; targetNode.style.display = 'block'; }); function createTextareaComponent() { var init = document.createElement('cubx-core-init'); init.style.display = 'none'; init.appendChild(createSlotInit('label', '"Textarea label"')); init.appendChild(createSlotInit('value', '"Value of textarea"')); init.appendChild(createSlotInit('cols', '40')); init.appendChild(createSlotInit('rows', '8')); var testTextarea = document.createElement('test-textarea'); testTextarea.setAttribute('cubx-webpackage-id', 'this'); testTextarea.appendChild(init); return testTextarea; } function createSlotInit(slotName, slotValue) { var slotInit = document.createElement('cubx-core-slot-init'); slotInit.setAttribute('slot', slotName); slotInit.innerHTML = slotValue; return slotInit; } })() </script> </body> </html> |