Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

component and partial props #685

Closed
Manborough opened this issue Apr 13, 2021 · 7 comments
Closed

component and partial props #685

Manborough opened this issue Apr 13, 2021 · 7 comments
Labels
question Further information is requested

Comments

@Manborough
Copy link

This is a cool library, there seems to be quite a lack of server side component libraries for JS.
I wanted to ask if there's any way currently to pass props between components and partials?

Given this

const view = await render('./app/views/one.html', {states: state })
// Render is just a wrapper around boxwood so I can pass in a template file and get back html.

it seems that in the component the state property seems to be global and can be accessed directly from layout. Perhaps it could be walled off instead and passed in directly like vue or svelte would.

something like this.

// template_file_1.html
<import layout from="./layout.html" />

<layout sub_state={state.events} >
     Slotted content
</layout>
//layout.html
<if sub_state.state>
 {sub_state.name}
<end>

<slot/>
@emilos
Copy link
Contributor

emilos commented Apr 13, 2021

@Manborough thanks for the kind words!

It is possible to pass props between components and partials, here's a simple example:

Explicit props

// pages/home.html
<import layout from="layouts/default.html"/>

<layout {title}>
  <h1>Hello, {name}!</h1>
</layout>
// layouts/default.html

<html>
  <head partial="./partials/head.html" {title} />
  <body>
    <slot/>
  </body>
</html>
// layouts/partials/head.html

<title>{title}</title>

The above shows the explicit shorthand syntax, you can explicitly pass values. Longer syntax looks like this:

<layout title="{title}">

should also work.

Implicit props

You can also pass values implicitly, using the globals keyword, e.g.

// layouts/partials.head.html

<title>{globals.title}</title>

In this case, you no longer need to pass the title. I prefer the explicit way, but this might help in some scenarios too.

Danger zone

The syntax you've shown:

<layout title={title}>
// or

<layout title={ title }>

is not recommended (lack of quotes). I decided to use a standard html parser under the hood instead of writing a new one. It allows you to reuse existing html tools (e.g. for color highlighting, formatting, linting).

I hope this answers your question, better docs are in progress and I'll try to include it there.

@emilos emilos added the question Further information is requested label Apr 13, 2021
@Manborough
Copy link
Author

I hope this answers your question, better docs are in progress and I'll try to include it there.

It does! Thank you :)

I've played around with a little bit already and ran into a related question. When I pass props through using this syntax, should the variable in the component be accessed using things? Currently it only works when you use states.

I was expecting that it would alias to the attribute name.

<button_1 things="{states}">

@emilos
Copy link
Contributor

emilos commented Apr 14, 2021

@Manborough I think it should work already, here's a spec that I've added to demonstrate:

3c9c78b

the lib is still in progress though, so it might have some rough edges. Can you show a full example? That would help a lot to repro

@Manborough
Copy link
Author

Sure thing. I'm building a UI to assemble state machines, hence the state this and that.

// render_boxwood.mjs

import boxwood from 'boxwood'
const { compile, escape } = boxwood
import { readFile } from 'fs/promises'

export async function render(path, params) {
	let result = await readFile(path, 'utf8', (err, data) => err ? console.log(err) : data)
	
	const { template, errors } = await compile(result, {cache: false, paths: ['./app/views']})

	console.log(errors)

	if (errors.length > 0) {
		throw JSON.stringify(errors)
	}
	
	return template(params, escape)
}
// index.mjs

import { render } from './render_boxwood.mjs'

fastify.get('/', async (request, reply) => {
  const stateChart = await prisma.$queryRaw(chartcte, 'null')
  const state = await stateChart[0].state.sort((a, b) => a.order - b.order)
  
  const view = await render('./app/views/example.html', {states: state })
  reply.type('text/html').send(view)

})
// ./example.html
<import state from="./state.html" />
<div class="flex space-x-4 p-4">
	<state foo="{states}">
	</state>
</div>
// ./state.html

// If i change states in the for loop to foo I get an error.
//"Cannot read property 'length' of undefined"

<for state of states>
	<div class="border p-2 m-2">
		{state.value}
	</div>
</for>

The states object passed into the render function looks a bit like this.

[
  {
     id: '1',
     lvl: 0,
     name: 'Received',
     order: 1,
     value: 'received',
     events: { Whatever: null },
     states: null,
     initial: null,
     parent_id: null
   },
   {
     id: '2',
     lvl: 0,
     name: 'Design',
     order: 2,
     value: 'design',
     events: null,
     states: [{name: 'substates' }],
     initial: 'outsourced',
     parent_id: null
   }
 ]

@Manborough
Copy link
Author

I just tried out your example too, it works fine, so there's something up with the way I'm doing it currently. Could be the for loop, or perhaps the repetition in my naming. (Or a silly mistake of course)

@emilos
Copy link
Contributor

emilos commented Apr 15, 2021

@Manborough thanks for the great example. I've pushed a fix and released it as v0.53.4. I'm reworking the compiler right now, which will hopefully simplify things and avoid this type of errors.

@Manborough
Copy link
Author

Sounds great. I'll close off this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants