How to invoke Jinja processing in my card JS code?

I am developing a card in JS. I would like to let my users use Jinja templates in the configuration.

But then I will have to process that inside my JS and I don’t know how to. I guess I’ll have to import a Jinja library, load up some context for the processing (values of variables), load the config as a template and ask Jinja to process it, so I can use the result…

How can I do this? Is there any example available that you know of? It would be great to start from something in the context of HASS, instead of having to go through generic documentation.

Thanks in advance!

Hi, I don’t know how to do it, but an example would be the Mushroom Template Card

1 Like

:thinking: thanks, but that seems to be TypeScript, not JavaScript…

And I can’t find any references in the code to “Jinja”…

Can anybody please help? Thanks!

Typescript is just JavaScript with types. Quite literally.

Remove the type and it’ll be JavaScript.

Ok, so remove the type… from what?

I don’t see any Jinja stuff in that project that was linked… :thinking:

:thinking::thinking: https://github.com/piitaya/lovelace-mushroom/blob/3ffaa21d7dd0e5e74910f9257e8b0365426415f9/src/ha/data/ws-templates.ts#L15-L29

You can help yourself with the search for more info. :+1:t2:
And arguably some googling.

1 Like

Googling is easy once you know what to search for… :sweat_smile: I did a lot of googling before asking.

That bit of code has a lot of things (apart from types) throwing me off, but I get the point: I’m not looking for Jinja references, I am looking for templates. It’s a pity because that term has a lot more ambiguity, means a ton of things inside HASS (not to mention in general!).

I guess the render_template function is what I want to call in my Javascript. But it is not in scope, it seems it’s a back-end call. Which could be overkill for my case.

Maybe I’m better off allowing JS scripting in my card config (not Jinja templating) and use eval

You if mean to distribute your work, you might want to read this section from MDN and this article.

Thanks, that’s quite useful. I was aware of the dangers of code injection (in this case, stuff coming from YAML configuration, so it’s for admins only), but the other issues concerning performance, variable scopes, etc, and the alternative Function and indirect evals, these are all new to me and good to know. :+1:

If I end up using eval or similar, I’ll surely go for one of the more restrictive versions. Thanks

If you’re still looking for a way to add template support to your custom card, I just released ha-nunjucks for this very purpose. It offers a much easier way to implement template supports in custom cards by using nunjucks and the frontend hass object. The caveat being that the syntax is sometimes slightly different and I have to reimplement all the Home Assistant template extensions in TypeScript.

While the method used by card-mod and mushroom is better, it is difficult to understand and implement. Implementing ha-nunjucks is as simple as a function call.

1 Like

Interesting! Very interesting!

But that is TypeScript, not JS… is there any way to use it in a plain JS card like mine?

Another question, after briefly scrolling through your documentation… how can you add context for the templates? I mean, extra variables that the template can reference.

Thanks!

I like to call TypeScript the lipstick on the pig that is JavaScript - they’re functionally the same thing but TypeScript is prettier. TypeScript compiles into JavaScript. Anything written in Typescript gets compiled and distributed as JavaScript. So yes, you can! You should be able to use and import it all the same because the distributed files are js files with additional d.ts TypeScript declaration files, the latter of which are ignored when coding in JavaScript.

As for nunjucks context. I’ve already programmed in several Home Assistant template functions which are included by default. If there are more that you want to add or need you can either make a feature request on the repo or we can work collaboratively through pull requests to do so.

Cool.

I wasn’t asking about adding known HASS functions, but arbitrary values from any context at all. In my case, it would be items from the card config, and Todoist tasks (that’s what my card handles).

Stuff like this that I got from the nunjucks online docs:

nunjucks.renderString('Hello {{ username }}', { username: 'James' });

That username in this example could be anything, including complex objects with many field values in them. I guess your code would simply have to pass them on to nunjucks.

I think a nice way to do it would be to separate the act of rendering from the act of defining context. So your library could have a function call just to add context incrementally, and then a simple function to render. Something like this:

ha-nunjucks.addContext({ username: 'James' });
ha-nunjucks.addContext({ goes: 'here' });
ha-nunjucks.addContext({ tasklist: someObject });
ha-nunjucks.render('the template text goes {{ goes }}, using any parts of the context it wants');

Ah gotcha. Good idea, I should add an option to add custom context. In order to keep it as simple as an import and function call I’m thinking something like this:

ha-nunjucks.renderTemplate(this.hass, templateString, { foo: 'bar', baz: 'bah'})

Can you make a feature request on the repo so I don’t forget?

Edit: custom context added in v1.2.0.

1 Like

Thanks, that looks great!

I hope I’m not getting too annoying, but I would appreciate some guidance about using this in my JS card.

Apart from my TypeScript ignorance, I’m also not good with JS - this is my first JS project and I was basically tweaking someone else’s project when things got totally out of hand :sweat_smile:

I am just guessing, but I would need to…

  • Move all the compiled *.js files from dist directory into my project directory?
  • include… which one(s)?

Thanks in advance!

My first Home Assistant project six months ago was a fork of a fork, and lot’s of projects are built off of other’s work. We all start somewhere :smile:. I didn’t even learn JavaScript and TypeScript until my last job about three years ago, now TypeScript is my favorite language. What languages do you know?

You should be using npm to manage your project. It’s a package manger and can also be used to manage JavaScript/TypeScript projects. ha-nunjucks is a JavaScript/TypeScript package, and it can be installed from npmjs by running the following command in the command line at the root folder of your project:

npm install ha-nunjucks

It should get downloaded to a node_modules folder. You should also run npm install to install any dependencies listed in package.json. From there you should be able to import and use it. Either using the newer import { renderTemplate } from 'ha-nunjucks' syntax or the older ha_nunjucks = require('ha-nunjucks') syntax.

1 Like

I’ve been around for more decades than I care to remember, so I’ve been through dozens of languages, starting from BASIC. My favorites would be the C/C++/C# family, but I haven’t had a chance to work on those for years, lately it’s been mostly PHP on the back-end.

I’ve used npm before, and I understand this better when I’m thinking of it as a “development environment”, but I don’t have npm on hass.io (or whatever the VM installation of a HASS OS is called).

And I don’t get how I’m supposed to ship my card to end-users with this, if it requires npm installation.

Shouldn’t there be some installation instructions for deployment? Different than the ones for development. Something explaining how a finished card available on HACS can be deployed to end-users, in a way that includes your package and the original nunjucks.

In my case, since I will only be doing JS code that doesn’t require compiles, I would try to work from that deployment scenario, and avoid npm and compilations altogether.

You need to bundle your code. A bundler will “compile” your code along with its dependencies (including ha-nunjuck") into its own package which you can then deploy and consume from the browser.

You might want to read up on JavaScript bundlers. Typescript is the same. I think the resistance you’re facing with typescript would be the unfamiliarity to the ecosystem.

Can’t blame you, it’s pretty convoluted.

@samuelthng thanks, that’s helpful.

I totally admit to resistance to facing the typescript ecosystem. :sweat_smile: But it’s mostly because my experience taught me that I shouldn’t face too many learning curves at once. Each of those things is a rabbit-hole, if I don’t have a stable position from which to approach them. And since I am new to JS, Home Assistant, Lovelace, Todoist API I’m working with, etc., I’m trying to avoid as much confusion as I can. I’m sure I will eventually want to learn these properly, though. I’ll get there, hopefully.

About the bundling - anything specific for HASS? For example, I’ve faced this problem, I guess my current issue is an extension of that mechanism. Do you know if that sort of thing is documented somewhere in a way that is specific to HASS?

Thanks!