Leaf API
defineScope
Section titled “defineScope”defineScope is the most important API because it provides isolation between scopes, thus maintaining a clean code structure. DefineScope also creates the logic for your application’s UI.
Example
import { defineScope } from "https://cdn.jsdelivr.net/gh/Rahmad2830/Leaf@v1.0.1/dist/Leaf.min.js"
defineScope("greeter", () => { //your code here
//must be return object even when its empty return {}})defineScope must be always return object even when its empty. If not, it will generate error message
Context Object
Section titled “Context Object”Leaf have 2 main context object, first at defineScope level, second is in the function level.
Context in scope level
Section titled “Context in scope level”This context is in the defineScope params function.
//context placed in heredefineScope("any", (context) => { //code goes here})This context scope has three main properties: root, which retrieves the element where the data-scope is defined. targets, which marks (retrieves) the element. values, which retrieves the value of other data-* elements within the root element.
You can also use object destruction to invoke the context. Example
//context placed in heredefineScope("any", ({ root, targets, values }) => { //code goes here})- targets
Targets is useful for marking elements to be retrieved. You can mark multiple elements with the same target data using targets.all.[targets_name]. However, remember that using targets.all.[targets_name] will result in an array of elements. To process it, it must be looped first.
Example
<div data-scope="any"> <div data-target="hello">Something</div>
<p data-target="world">Something</p> <div data-target="world">Something</div></div>defineScope("any", ({ targets }) => { const greet = targets.hello //take element with data-target="hello" console.log(greet)
const allWorld = targets.all.world //take all element with data-target="world" allWorld.forEach(element => console.log(element))})You can use all methods for elements. For example: greet.id to get the element ID, greet.hidden = true to set the element’s visibility, etc.
- root
root is useful for retrieving elements that have the data-scope attribute attached. Example: HTML
<div data-scope="any"> <!-- your code here --></div>javascript
defineScope("any", ({ root }) => { root.hidden = true})You can use all methods for elements. For example: root.id to get the element ID, root.hidden = true to set the element’s visibility, etc.
- values
Imagine if you needed other data in the scope, then you could put it in the data-* attribute. values is used to retrieve the value from the data- attribute in the scope element. If you write data-status=“pending”, you can call it with the prefix values.status.
Example:
<div data-scope="any" data-status="pending"> <!-- your code here --></div>defineScope("any", ({ values }) => { console.log(values.status) //output "pending"})Always remember that values always return strings. If you pass a number, for example, data-id=“5,” then the number 5 will default to a string. To change this, you must manually change Number(values.id)
Context in function level
Section titled “Context in function level”The context object at the function level is located in the function parameters that you create in defineScope.
Example:
defineScope("any", () => { //context in function level placed here function greet(context) { console.log(context) }})You can also use object destruction to call this context. Example:
defineScope("any", () => { //context in function level placed here function greet({ element, event, params }) { //do something }})The context at this level also has three main properties: element, used to select the element to which this function is attached. event, which is the event in a regular listener (e.g., event.target.closest). params used to retrieve data-* values within this element. Since the element to which this function is attached must be a data-action, it is more accurately called an action context.
- element
element is useful for selecting elements that have functions attached to them, in this case elements that have data-action attached to them. Maybe you need element.id or something similar, then this will be very useful.
Example:
<div data-scope="any"> <div data-target="hello">Something</div>
<button data-action="click->toggle">hide</button></div>defineScope("any", ({ targets }) => { const hello = targets.hello
function toggle({ element }) { hello.hidden = !hello.hidden //set the button inner text element.textContent = hello.hidden === true ? "show" : "hide" }
return { toggle }})The code above will change the inner text of the button to show or hide according to the condition of the hello element.
- event
context event does not need to be explained in too much detail, it is the same as the event in the listener parameter.
Example:
<div data-scope="any"> <label for="name">Your name</label> <input type="text" name="name" id="name" data-action="input->run" />
<div data-target="output"></div></div>defineScope("any", ({ targets }) => { const output = targets.output
function run({ event }) { output.textContent = event.target.value }
return { run }})The code above will do something like two-way binding, where when you write your name in the input, the output will be updated automatically.
- params
params is used to retrieve the value from data-* within an element that has a data-action. Think of it like a function parameter. To retrieve it, use the prefix params.[data-name]. For example, if you’re looking for the ID data-id="5", you can retrieve it using params.id.
Example:
<div data-scope="any"> <button data-action="click->getUser" data-id="5">hide</button></div>defineScope("any", () => { function getUser({ params }) { console.log(Number(params.id)) //output "5" (string) }})Note that the resulting value of params.id is a string, and will always be a string. You must manually change it to Number(params.id) as well as the boolean value.