als-component

0.9.82 • Public • Published

Als-component

being tested

Table of contents

About

Dynamicly manage dom content as components and states on frontend and backend. You can do it with Vite like you do it in React, on Express as middleware or simply in frontend.

We are closer than ever to final release!

New in 0.9.82

  • Use $ instead $C

New in 0.9.8

  • Component = require('als-component').get() - get Component after clearing cache
  • Component.export - changed and fixed. Now it's return errors.
  • Component.create() - checks if Component not exists

New in 0.9.7

  • if component doesnt return enything, no error, the result 'undefined'
  • inside onLoad function available this (component it self)

New in 0.9.6

  • Export for Component.actions fixed

New in 0.9.5

  • import is separated to als-front-import
  • Component.components
  • Component.vars
  • Component.methods
  • Component.methods.$
  • Component.actions
  • Component.dispatch
  • Component.ref(ref,add='')
  • Component.qs
  • Component.qsa
  • component.vars
  • component.methods
  • component.methods.$
  • component.actions.$
  • component.ids.id = {id,data,get:element,update}
  • component.onLoad() - for backend
  • $C = Component (and not new Component())
    • no $CComponentName and $cComponentName

Get started

Instalation and Cdn

  1. Install the package with npm i als-component
  2. Add component.js to your head inside html
<head>
  <script src="node_modules/als-component/component.js"></script>
</head>
  1. Use Component class

Basic syntax

The component.js has class Component which do all the magic behind the scenes. You need to create new component and then get it result or update it to existing html element.

The syntax:

// Static methods
Component.components // includes all components
Component.ref(ref,add='') // select dom element with ref="ref" and add (additional selector)
Component.qs(selector,dom=document) // dom.querySelector(selector)
Component.qsa(selector,dom=document) // [...dom.querySelectorAll(selector)]
Component.vars // empty object for variables
Component.actions // empty object for actions and $ method
Component.dispatch(componentName,action,data,id)

Component == window.$ // true - by default $ available as reference to Component

let c = new Component(ComponentName,fn,data)
c.update(data,id,updateElement=true) // return created dom html element
c.get(data,id) // return string html
c.element(id) // return component's element, if id - with specific id
c.ref(ref,add) // return element inside component's element with selector [ref=ref]add
c.ids[id] = {update,get,data,element,id} // data and elements are getters
c.methods // object for methods
c.methods.$ // getter for component object - available as this.$ in method
c.actions // object for action functions
c.actions.dispatch(action,data,id)
c.actions.$ // getter for component object - available as this.$ in actions
c.vars // object for variables

Parameters:

  • new Component(ComponentName,fn,data)

    • ComponentName - Component's name
      • Available as Component.ComponentName or as $.ComponentName
    • fn - function(data,id) which has to return html string code
      • id parameter necessary only then you use more then one component
    • data - "the state" for component
      • available as Component.componentName.data or Component.componentName.ids.id.data if there is id
  • update(data,id,updateElement=true)

    • data - updates the "state".
      • If data undefined, will be used data from component object (the state)
      • data has to be new object
    • id - specify which data to use and which element to update
      • will create object componet.id= {id,data,element,update,get}
        • element is a getter
    • updateElement - if false, update will return fn result only (without updating html element)
      • true by default - updating data and html element
  • get(data,id) - same as update(data,id,false)

  • element(id)

    • if id undefined return component main element (with component="componentname")
    • if id not undefined return component element with given id
  • ref(ref,add='')

    • return dom element with selector ``[component={componentName}] [ref="{ref}"]add`

Example

  <div component="counter"></div>
  <script>
new $('counter',function() {
  if(this.data <0) this.data = 0
  return /*html*/`<div>
       <button onclick="$.Counter.update($.Counter.data+1)">+</button>
       <span>${this.data}</span>   
       <button onclick="$.Counter.update($.Counter.data-1)">-</button>
  </div>`
}).update(0)
</script>

Component.create

There is static method Component.create() which equivalent to new Component(). The method, checking if component allready exists and create new one if not. Return the component obj.

Syntax:

Component.create(ComponentName,fn,data):object instance of Component

Life cycle for update/get

You can add functions for executing on different stages of binding process.

Life cycle for update/get

  1. this.before(data,id)
  2. this.fn(data,id)
  3. Component.onDom(element,parentTemplate)
  4. this.onDom(element,parentTemplate)
  5. this.onFirstMount(data,id)
  6. this.onMount(data,id)

Here example for hooks:

   <div component="counter"></div>
   <script>
new $('counter',function() {
   if(this.data <0) this.data = 0
   return /*html*/`<div>
         <button onclick="$.Counter.update($.Counter.data+1)">+</button>
         <span>${this.data}</span>   
         <button onclick="$.Counter.update($.Counter.data-1)">-</button>
   </div>`
})


// Before running fn
$.Counter.before = function(data,id) {
   console.log('before',data)
}
// Then dom element is ready, but not mounted yet
// Runing in all components
Component.onDom = function(element) {
   console.log('Component.onDom')
}
// Then dom element is ready, but not mounted yet
$.Counter.onDom = function(element) {
   console.log('Counter.onDom')
}
// Then dom mounted first time - runing only once
$.Counter.onFirstMount = function(data,id) {
   console.log('onFirstMount',data)
}
// Runing every time after dom has mounted
$.Counter.onMount = function(data,id) {
   console.log('onMount',data)
}
 
$.Counter.update(0)
 </script>

On example above, on first run youll get on console:

before 0
Component.onDom
Counter.onDom
onFirstMount 0
onMount 0

After clicking on minus:

before -1
Component.onDom
Counter.onDom
onMount 0

Simple redux system

Each Component object has actions object. You can add to this objects your actions for modifying data. The action has to return new data for update the component.

  • For using actions you need to run dispatch method which update component with data that action return
  • Inside every action you can use this.$ which reference to Component's object

Also you have Component.actions object and Component.dispatch(componentName,action,data,id) which update component with componentName with data that action will return.

Syntax

let Test = new Component('test',function() {})
Test.actions.testing = function(data,id) {
  console.log(this.$) // Test component
  return data
}

Test.dispatch('testing',{})

Let's see Todos app example that manage todos with localstorage and containes 3 files:

  1. index.html
  2. Todos component
  3. Todo component

Part of index.html

<script src="/node_modules/als-component/component.js"></script>

<input type="text" placeholder="add todo" 
  onchange="Todos.dispatch('add',this)">
<div component="todos"></div>

<script src="todo.js"></script>
<script src="todos.js"></script>

todos.js

let Todos = new Component('todos',function(data) {
   this.vars.isHr = true
   return /*html*/`<div>
      ${data.map(todo => $.Todo.get(todo,todo.id)).join('')}
   </div>`
})

Todos.before = function(data,id) {
   if(data == undefined) {
      data = localStorage.getItem('todos') || {}
      data = JSON.parse(data)
   }
   data.sort((a, b) => a.completed > b.completed ? 1 : -1);
   localStorage.setItem('todos',JSON.stringify(data))
   this.data = data
}

Todos.actions.add = function(element) {
   let newTodo = {
      name:element.value,
      completed:false,
      id:(Math.random() + 1).toString(36).substring(7)
   }
   element.value = ''
   return [...this.$.data,newTodo]
}

Todos.actions.remove = function(id) {
   return this.$.data.filter(obj => obj.id !== id)
}

Todos.actions.completed = function(id) {
   return this.$.data.map(obj => {
      if(obj.id == id) obj.completed = !obj.completed
      return obj
   })
}

Todos.update()

todo.js

new Component('todo',function({name,id,completed,hr=''}){
   if(completed && Todos.vars.isHr) {
      hr = /*html*/`<hr>`
      Todos.vars.isHr = false
   }
   return /*html*/`<div>
      ${hr}
      <button onclick="Todos.dispatch('remove','${id}')">&times;</button>
      <span onclick="Todos.dispatch('completed','${id}')"
         ${completed ? 'style="text-decoration: line-through;"' : ''}
      >${name}</span>
   </div>`
})

Quick snippets and highlighted html

To show html highlighted code inside string in js, use es6-string-html plugin in vsCode and

/*html*/`html code`
  1. Install plugin: es6-string-html plugin.

  2. File > Preferences > Configure user snippets > javascript

  3. Add:

"html": {
   "prefix": "html",
   "body": ["/*html*/`$1`"],
   "description": "colored html"
},
"rhtml": {
   "prefix": "rhtml",
   "body": ["return /*html*/`$1`"],
   "description": "return colored html"
},

Build with Vite

You can use Vite for building projects as you do in React.

Just do the folowing:

  1. Install Vite with npm create vite@latest (choose vanila)
  2. install all packages for Vite (npm install) and then Component npm i als-component
  3. Update main.js with the folowing:
import {Component} from 'als-component'
new Component('app',function() {
  return /*html*/`
  <div>Hello From component App</div>
  `
}).update()

That's all!

Export in express

You can use components inside your Express and then export them to frontend. Each time you add new Component, you need to export the updated Component class as shown on example below.

server.js

let express = require('express')
let app = express()
let {Component,Export,get} = require('als-component')
let consoleLogErrors = true

let get$ = (req,res,next) => {
   req.Component = get()
   next()
}

app.get('/:name',[get$,
   (req,res) => {
      let {Component} = req
      new Component('App',function(data) {
         return /*html*/`
         <div>Hello ${data.name}</div>
         `
      })
      $.App.onLoad = function() {
         console.log('hello '+this.data.name)
      }


      let name = req.params.name
   return res.end (/*html*/`<!DOCTYPE html>
<html lang="en">
   <head>
      <title>Component export</title>
   </head>
   <body>
      <input type="text" value="${name}" 
         oninput="Component.App.update({name:this.value})">
      ${Component.App.get({name})}
   </body>
   <script>${Export(Component,consoleLogErrors)}</script>
</html>
   `)
}])
app.listen(3000)

Example above, showing the way for using Component on frontent and on backend. Here are the highlights:

  1. Define req.Component widht als-component.get method as middleware on route you want to use it.
  2. Use Export method for exporting Component to frontend.
  3. Use onLoad hook to add function which will runs then all content will be loaded

Use get() method to require component and use it as middleware, to include on each route only it's relevant components and methods.

Readme

Keywords

none

Package Sidebar

Install

npm i als-component

Weekly Downloads

0

Version

0.9.82

License

MIT

Unpacked Size

21 kB

Total Files

5

Last publish

Collaborators

  • alexsorkin