Giter Club home page Giter Club logo

jbind's Introduction

jBind

jBind is a lightweight library for binding HTML Element text and attributes to live, updatable values that are supplied by Kotlin/JS code.

Installing

Until I get around to bothering to figuring out how to publish my stuff to Maven Central, or else until GitHub gets around to fixing its dumb package system to allow unauthenticated downloads, installing this library will unfortunately be pretty awkward. Here's how you'd do it in a Kotlin DSL Gradle script, and it should translate pretty easily to whatever similar system you may use.

repositories {
    //...other ones
    maven {
        url = uri("https://maven.pkg.github.com/tradeJmark/jBind")
        credentials {
            username = githubActor ?: System.getenv("GITHUB_ACTOR")
            password = githubToken ?: System.getenv("GITHUB_TOKEN")
        }
    }
}

dependencies {
    //...other ones
    implementation("ca.tradejmark.jbind:jbind:0.0.1")
}

And then, of course, you'd have to either set those variables or use the environment variables, where GIGHUB_ACTOR is your GitHub username and GITHUB_TOKEN is a Personal Access Token.

Usage

Specifying Bindings

In jBind, bound values are each identified by a Bind Location, subdivided into a Bind Path, Object Name, and Value Name. The Path may contain multiple dot-separated values, and the Object Name and Value Name are appended to the Path, also using dot-separation. So, for example, the location my.path.element.name references the value name of an object named element located at my.path. In HTML, you can bind the text of an object to a value by specifying the value's Bind Location in the data-jbind-text attribute, as shown below.

<div data-jbind-text="my.path.element.name"></div>

As values are supplied for the my.path.element.name location, the div will be updated accordingly. For example, if the value "Text" were supplied at that location, the div would become:

<div data-jbind-text="my.path.element.name">Text</div>

Any subsequent values at that location would cause the div to automatically update accordingly.

Attribute binding is done by specifying all attributes to be bound in data-jbind-attributes (comma-separated), then giving those attributes Bind Locations as values, as in this example:

<div data-jbind-attributes="hidden,data-status" 
     hidden="data.div.hidden" 
     data-status="data.div.status">
</div>

At bind-time, the locations will be replaced with the supplied values.

Kotlin HTML DSL

If you are using kotlinx.html, you can specify these bindings in a type-safe way as shown in the following example:

div {
    val path = BindPath("my").sub("path")
    bindText(path.obj("element").value("name"))
    val divObject = path.obj("div")
    bindAttributes(mapOf(
        "hidden" to divObject.value("hidden"),
        "data-status" to divObject.value("status")
    ))
}

Initiating the binding

In your code, in order to initiate the binding, you need to call the JBind::bind method, supplying it a root element (the entire subtree of which will be bound) and a Provider which knows where to find the values. Here is an example:

val element = document.body!!.getElementById("bind-root")
JBind.bind(element, WebSocketProvider())

Providers

A Provider knows how to supply a flow of values for a provided location. A Provider could be as simple as this:

object StaticProvider: Provider {
    override fun getValue(location: BindValueLocation): Flow<String> {
        if (location == BindPath("mypath").obj("object").value("name")) {
            return flow { emit("The Name") }
        }
        else throw UnavailableError(location)
    }
}

In general a Provider like that would have fairly limited use, but you can create a custom Provider for almost any use you could need, like reading from a database or calling back to the server.

WebSocketProvider is supplied by the library, and will kick the can of providing values down to the server over a WebSocket. By default it will connect to the current host at the root over a plain ws:// connection, but you can supply a custom WebSocket if you want to use a different path or wss://:

val ws = WebSocket("wss://somesite.com/jbind")
val provider = WebSocketProvider(ws)
JBind.bind(document.body!!, provider)

If you are using Ktor as your server, you can include jBind in your backend dependencies, and then use the JBind plugin to accept connections from WebSocketProvider instances:

fun Application.main() {
    install(JBind)
    routing {
        route("jbind") {
            val provider: Provider = MyProviderForGettingValuesFromTheDBOrWhatever()
            jBind(provider)
        }
    }
}

In tandem with the appropriate WebSocketProvider on the client-end, this should rather seamlessly behave as though the server-side Provider were supplied directly to the client.

Upcoming

In the near future, I plan to add facilities for arrays of objects, and also the ability to bind an entire object to an element. What either of those might look like is still pretty fluid, so stay tuned.

HQs

I don't have FAQs on my stuff because I've never made anything famous enough for people to frequently ask questions about it, but here are some hypothetical questions.

Q: Can I consume this from JavaScript/TypeScript?

A: Not really.

I'd be interested in making that work maybe at some point, but right now the public interface relies on Kotlin stuff like Flow that doesn't translate. For now and the foreseeable future, you'd mostly want to use this library if you were already making a frontend in Kotlin/JS.

Q: Is this production ready?

A: Not really.

I mean, all of the tests pass and everything seems to work, so if you're interested, I say have at it, but it's never been used in production up to now, so you'd be on an adventure.

jbind's People

Contributors

tradejmark avatar

Watchers

 avatar

jbind's Issues

Add functionality for middleman processors and binding inner elements instead of just inner text

Say the content you want to bind to the text of an element is supposed to have a link in it. Now what? You make a separate bind for the link? What if you want to remove the link without altering the static HTML you're serving, because the link is essentially content and not structure? And what about the text that comes after the link? How do you represent that? This library just doesn't much work at all for scenarios like this right now. This functionality is mainly to allow you to, for example, process the provided value as Markdown and produce an HTML element to inject into the parent's content, which would really solve this. It also adds interesting potential for scenarios like decrypting values if users have permissions to view them.

Add Decrypt Transformation

Decryption was an example of functionality that I could think of for Transformations, and I think it's a nice-to-have to offer a default one.

Allow binding of entire objects

This would bind all values associated with a particular element to associated attributes. A deserializer will also be provided to recover the object given the element (potentially useful from within a web component, for example).

Add interface from pure JS

Would be kind of cool if you could access the library from JS. I think I would want to make some sort of mapping between Flows and web workers, but it's probably possible.

Implement arrays

This will allow for arrays, where children of an array parent are bound relative to the array child of the same index.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.