DEV Community

Cover image for Using Dynamic Components And a Pattern I Devised Myself to Create a No Code Web Interface Builder
Matt Anderson
Matt Anderson

Posted on

Using Dynamic Components And a Pattern I Devised Myself to Create a No Code Web Interface Builder

About two years ago I discovered VueJS, around the same time that “no code” solutions began to hit the shelves. I say I discovered Vue, I’d played with Vue, creating the ToDo list app (as you do/ did), but somewhere (I can’t remember where exactly) I encountered the dynamic component and this set me off on a two year journey developing what has now become yakety.co.uk, an interface builder that connects to APIs and cloud services. This article explains how the pattern I created allows for infinitely complex web interfaces to be developed, quickly, easily and using any back-end platform (as it is completely front-end driven).

Quick intro to Dynamic Components

For those of you that aren’t aware of them, may I introduce: Dynamic Components:

<component v-bind:is=”currentTabComponent”></component>

To quote the Vue docs:

Sometimes, it’s useful to dynamically switch between components, like in a tabbed interface.

This was a virtual apple dropping on my head. I saw an opportunity to use this component to create something I’d wanted to create for a while but was beaten to it: A Medium.com style editor. I’m a competitive person by nature so I thought to myself “I’ll still create an editor, only thanks to dynamic components, it will be better!”

I have no early versions to show you so you’ll have to make do with its current incarnation: https://yakety.co.uk/demo-article?edit

So "how does it work" you say? Read on.

1. Components

To build an interface builder the first thing you need are components. I decided to speed things up (he says, two years after starting work on this) by using Buefy, a VueJS component suite that uses styles from the (still quite well known in development circles I think?) Bulma.

You can add Buefy components into any project (that uses VueJS) like this:

<b-input type="is-danger" @input="handleInput"></b-input>

Which was a great speed gain, but I needed to have more (dynamic) control over the way these components look and behave so (out of pure necessity) I created a wrapper component, the template for which looks something like this:

<b-field
  :label="items.label"
  :message="items.message">
  <b-input
    :value="items.value"
    :name="items.name"
    :type="items.subtype"
    @input="handleInput">
  </b-input>
</b-field>

I named this component s-input to avoid a clash, then I looked at how I could fetch and set the properties from the server.

I must also mention, I had this idea that all the data required for the page would be fetched all at once and made available to all components by attaching it to the window object in the browser. That felt like a necessity in order allow the dynamic component to be well, dynamic. I wanted all the components to have access to all the data they may need so that I didn’t box myself into a development corner further down the road.

So here’s what I did (minus the endless trial and error).

2. Server

As with most web applications a page request is made and it hits a controller.

The objective here is to get all the properties required for all the components you wish to display on a page. So using the URI which for the Demo Article example link above is simply demo-article we run a query that fetches all the component properties for that particular route.

Let’s say we want to display an input and a button. In the most simple example, the query could return the following JSON:

[
  {
    "is": "s-input",
    "type": "text",
    "name": "Some input"
  },
  {
    "is": "s-button",
    "text": "Click Me"
  }
]

Then in a component dedicated to displaying other components (by using the dynamic component), we can loop this data and display our actual components:

<component
  v-for="(item, index) in components"
  :key="index"
  :is="item.is"
  :properties="item"
>
</component>

:is="item.is" tells the dynamic component which component to display.:properties="item" prop is used to pass the properties to the component, thus determining its behaviour. And of course, the loop is iterating, in this case, over the two JSON ‘blocks’ as I call them, so we have control over a linear flow of components, just like Medium.com's editor and voila:

Alt Text

That is as simple an explanation as I can give to the underlying pattern I used to create interfaces with Yakety. To create more complex interfaces involving columns and heavily nested components would take much explanation and I don’t want this to turn into War and Peace so I’ll stop there for now. If there is sufficient interest then of course I will develop this into a series in which I target specific parts of the pattern that are harder to explain and give you the recipes for developing your own dynamic interfaces, interfaces that are controlled entirely from a database. Which brings me to the last part of the article…

3. Database

The biggest takeaway from what I have achieved here, isn’t the use of dynamic components in VueJS (although that is pivotal to the whole pattern working). The major discovery I made, was to allow for the construction of an entire (or partial) interface using only a database and a bunch of components that, for the most part, are empty shells or vessels. This removes the need for both large (and multiple) templates and logic heavy controllers.

Just think of the possibilities that have opened up (or view Yakety and see to see some of the possibilities I’ve thought of, in action). Here is a summary of things I have considered:

  • You can store and therefore manage styles using a database
  • You can store and manage behaviour using a database
  • You can see in an instant which components exist on a page
  • You can easily switch the order and location of a component
  • You could theoretically present different components to different users
  • You can allow for the creation of content and functionality using a no code solution for non-technical staff
  • You can duplicate, update, edit and so on, entire groups of pages or target properties of individual components with ease (you even have the power to do this with a script!) all thanks to your page being defined in a database rather than a file
  • The whole pattern is completely platform agnostic. I use VueJS and Laravel. What’s stopping you from using React and ExpressJS?
  • Perhaps there are even more benefits that I just haven’t thought of yet (let me know in the comments if you have other ideas about potential uses for the pattern)

I’ll stop there. As I mentioned, if I’ve been overly brief and you would like more detail, just leave a comment and I’ll be happy to expand on anything I’ve said either in a reply or, if the question warrants it, further articles.

I hope you have a good play with Yakety and enjoy using it. I look forward to hearing your thoughts and suggestions.

PS In case you’re wondering, the whole codebase is currently sitting in a private repo. I will eventually get around to making it public and I’ll write some documentation to accompany it.

Top comments (7)

Collapse
 
ackmandesu profile image
AckmanDESU

This is very interesting and something I want to build myself. I've been using Umbraco CMS for a while and always wondered if I could go static and create my own grid system. It just seemed like a whole lot of work.

The fact that it took you 2 years to get this far is very scary. Thank you for your work. I will definitely come back to this article.

Collapse
 
wahidn profile image
WahidN

You should look into web components. The company I work at uses Umbraco too and we are developing web components for easier and faster development. E.g for the grid you could creat a grid component that uses css grid, which is way more flexible than umbraco grid (which is actually deprecated in umbraco 8)

Collapse
 
ackmandesu profile image
AckmanDESU

Could you expand on this? I believe we are using the grid differently.

Collapse
 
yaketymatt profile image
Matt Anderson

Thanks! It took two years because I was doing a bunch of other stuff, I should have perhaps mentioned that to be clear! Plus all the trial and error stuff I can now share what I found to be "optimal" solutions to save some time. I'll make a public repo containing my code when I get chance...hopefully in under two years!

Collapse
 
seanmclem profile image
Seanmclem

I wish React had something like Dynamic Components. Looks like I'll have to dust off my Vue experience and build something fun like this. Just in time for Vue 3 😊

Collapse
 
devhammed profile image
Hammed Oyedele • Edited

There is Dynamic components, taking this JSON data:

[
{
  "is": "s-input",
  "type": "text",
  "name": "Some input"
},
{
  "is": "s-button",
  "text": "Click Me"
}
]

You can write a renderer like this:

import React from 'react'

import SInput from './components/SInput'
import SButton from './components/SButton'

const customComponents = {
   's-input': SInput,
   's-button': SButton
}

export default function DynamicRenderer ({ data }) {
  return data.map(({ is, ...props }) => React.createElement(is in customComponents ? customComponents[is] : is, props))
}

JSX compiles down to React.createElement and that is what we are leveraging on.
I am destructuring each item in the data to extract "is" property and passing the rest of prop to the rendered component or HTML element.
If the "is" property is not in customComponents object it will fallback to render it as normal HTML tag.

Collapse
 
yaketymatt profile image
Matt Anderson

I think it does Sean, try searching "dynamic component React" and you'll see a few tutorials. I haven't worked with React myself I must admit, so perhaps they have different meaning attached to "dynamic component". When I get chance I'll look into it myself and update the article.