Last active
February 7, 2017 17:45
-
-
Save machty/68afad4c03109f36d4f4cffaae3c170b to your computer and use it in GitHub Desktop.
embercommunity.slack.com #topic-forms discussion
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
joined #topic-forms, and invited @machty | |
locks [11:05 AM] | |
thar you go | |
machty [11:06 AM] | |
thank you! | |
[11:07] | |
@samselikoff @cowboyd | |
samselikoff [11:07 AM] | |
joined #topic-forms by invitation from @machty, along with @cowboyd. Also, @willrax joined. | |
machty [11:08 AM] | |
set the channel purpose: Best practices for building forms | |
machty [11:09 AM] | |
i'm interested in this topic because i had to build my first basic crud admin panel in like 3 years | |
samselikoff [11:09 AM] | |
boom | |
[11:09] | |
thanks dude | |
machty [11:09 AM] | |
and the amount of boilerplate and lack of conventions is outlandish | |
[11:09] | |
i'm gonna put together a gist of where i landed | |
samselikoff [11:09 AM] | |
ya. nice | |
[11:10] | |
every time I go back to rails and make a form it's incredible how simple and fast it is. I mean there's _so_ much you don't have to do | |
machty [11:10 AM] | |
yeah | |
samselikoff [11:10 AM] | |
form-for, integration with validations | |
locks [11:11 AM] | |
lack of crud scaffolding is a common complaint (edited) | |
willrax [11:11 AM] | |
nearly every form across our app has been built differently until we recently sat down and tried to work out some more conventions around it | |
locks [11:11 AM] | |
specifically from Rails devs | |
samselikoff [11:11 AM] | |
oof. ya will | |
[11:12] | |
and every team is basically doing this on their own | |
[11:12] | |
differently | |
willrax [11:12 AM] | |
yep | |
samselikoff [11:15 AM] | |
So the series we're making is not focused on solving problems of boilerplate, it's more in response to the "rise of ddau" we've seen in the community | |
[11:15] | |
I will wait for Charles | |
[11:15] | |
(however - the boilerplate/conventions problem is real and important and needs to be solved too) | |
[11:15] | |
they are related, I guess | |
fivetanley [11:18 AM] | |
joined #topic-forms. Also, @climbingnarc joined. | |
samselikoff [11:21 AM] | |
everybody use your brainpowers to ~ summon charles ~ (edited) | |
machty [11:22 AM] | |
or @fivetanley can just drive over and poke him | |
fivetanley [11:23 AM] | |
i’m sorry i have standup and then a very important bbq meeting | |
samselikoff [11:24 AM] | |
priorities | |
ryanto [11:40 AM] | |
joined #topic-forms. Also, @mmun joined. | |
machty [11:49 AM] | |
added this Markdown (raw) snippet: machty show and tell | |
# Code machty recently wrote | |
| |
for a CRUD section of an admin app. | |
| |
## Routing | |
| |
this.route('platform-users', function() { | |
this.route('edit', { path: 'edit/:user_id' }); | |
this.route('new'); | |
}); | |
| |
this.route('employee-logins', function() { | |
this.route('edit', { path: 'edit/:employee_login_id' }); | |
this.route('new'); | |
}); | |
| |
## Dir structure | |
| |
FYI Each route template renders a component. We don't use controllers | |
in any way. (This is kinda just a side point but sharing in case of | |
confusion.) | |
| |
▾ employee-logins/ | |
▾ edit/ | |
template.hbs | |
▾ form/ | |
component.js | |
template.hbs | |
▾ index/ | |
component.js | |
template.hbs | |
▾ new/ | |
component.js | |
template.hbs | |
| |
## Code | |
| |
Here are relevant snippets from the form component we use: | |
| |
| |
onSubmit: task(function*(data) { | |
let user = this.get('user') | |
user.setProperties(data) | |
| |
let [ error ] = yield this.get('notify').try(user.save()); | |
| |
let newUser = this.get('newUser'); | |
let notify = this.get('notify'); | |
| |
if (!error) { | |
if (newUser) { | |
notify.info("Successfully Created PIN", { | |
closeAfter: 5000 | |
}); | |
this.get('routing').transitionTo('employee-logins'); | |
} else { | |
notify.info("Changes Saved", { | |
closeAfter: 5000 | |
}); | |
} | |
} | |
}).drop(), | |
| |
goBack: task(function*() { | |
this.get('user').rollbackAttributes(); | |
this.get('routing').transitionTo('employee-logins') | |
}), | |
| |
We use `ember-notify` and overrode the default service as follows: | |
| |
```js | |
import Notify from 'ember-notify'; | |
import { task } from 'ember-concurrency'; | |
import { InvalidError } from 'ember-ajax/errors'; | |
| |
export default Notify.extend({ | |
try(promise) { | |
return this.get('_tryTask').perform(promise); | |
}, | |
_tryTask: task(function * (promise) { | |
try { | |
return [null, yield promise]; | |
} catch(e) { | |
this.reportError(e); | |
return [e]; | |
} | |
}), | |
reportError(e) { | |
if (e instanceof InvalidError) { | |
this.error(e.errors[0].detail); | |
} else { | |
this.error("Something went wrong, try again soon."); | |
} | |
}, | |
}); | |
``` | |
| |
Here's what the above accomplishes: | |
| |
1. We delegate to our overridden `notify` service to display an error banner | |
(via the `try` method). This is our hacky way of displaying | |
server-side validations. In a future iteration we'll do the work of | |
inlining the server-side validation errors in the form (would be nice | |
to have conventions surrounding this). | |
2. I use the Node/Go style approach for error handling, such that rather | |
than throwing exceptions, I just return a tuple of `[error, result]` | |
so I don't have to litter my code with try-catches, which sucks to | |
have to write and I feel doesn't compose well. | |
3. onSubmit is an EC task so that 1) I can drive loading state in the template | |
with `onSubmit.isRunning` and prevent multiple submits via `.drop()` | |
| |
Here's what sucks about the above that I hope to improve in the future: | |
| |
1. `NotifyService#try` is an OK pattern but it's weird to teach a | |
notification service about form submissions. I could probably move | |
that to a `services/forms` service or something. (This is a problem | |
specific to my code and not to the general discussion about lack of | |
conventions) | |
2. I haven't shown code for this, but I/we use a homegrown form | |
generator based on a json schema, e.g. describe all the fields and | |
expected validations via json/pojo and a component will render them | |
and do client-side validation. But now we have to retrofit it with | |
server-side error handling if we want to inline the errors | |
3. The rollbackAttributes cleanup that we have to do in our `goBack` | |
task (`goBack` itself is a break from conventions that I don't want to | |
go into right now) **MEGA SUCKS**. This is more an issue with Ember | |
Data conventions, which may some day be solved with store forking or | |
differentiating between in-progress / canonical records or something, | |
but it's all part of the presently crappy experience with forms. | |
| |
## General conclusions/musings | |
| |
Whatever solution/conventions we land on should assume the following: | |
| |
1. Internet connection is crappy | |
2. There are both client-side and server-side validations | |
3. It should be easy to display both client-side/server-side errors | |
inline (next to the offending field), or aggregated with all errors, | |
or in some `ember-notify`ish banner, or all of the above, and it | |
should be trivial to switch between any above approach. | |
4. Data-down actions up | |
5. The user is erratic and likes to double click stuff | |
6. It should be easy to drive button state with as in | |
[this | |
twiddle](https://ember-twiddle.com/#/f7a2c3b60502420a9e48a8c0edd9b279?fileTreeShown=false&numColumns=2&openFiles=templates.application.hbs%2Clocales.en.translations.js) | |
| |
Add Comment Collapse This snippet was truncated for display: see it in full. | |
machty [11:50 AM] | |
not sure if it's possible to render markdown snippets | |
[11:50] | |
plz don't use my brokeass code to hijack my startup | |
stevenwu [11:52 AM] | |
joined #topic-forms | |
mmun [11:53 AM] | |
the ▾ are a nice touch | |
[11:53] | |
i thought my editor was inserting some code folds haha | |
ryanto [11:58 AM] | |
machty our forms are pretty close to yours. we dont have a notify service / Either pattern, but the rest is similar | |
cowboyd [11:58 AM] | |
Oh hey yall | |
[11:58] | |
Started a twitter ball rolling and then ran off :slightly_smiling_face: | |
samselikoff [12:00 PM] | |
ya! | |
[12:01] | |
so charles - initial thoughts? what have you been thinking about | |
cowboyd [12:03 PM] | |
just reading read @machty’s gist | |
mmun [12:06 PM] | |
@machty: I will add to your musings… a lot of my boilerplate comes from making form objects because I only want to “commit" changes locally once they have been sent to and approved by the server. | |
ryanto [12:08 PM] | |
@mmun yup, likewise. a lot of boiler plate for us ends up being how to apply changes - two way bound, optimistic (before calling `.save()`), or pessimistic | |
samselikoff [12:09 PM] | |
mmun i think this should be configurable at the ember data layer. There's a nice pattern kris selden showed me where you can make a draftable subclass of a model | |
[12:09] | |
global Ember Data config, as well as `model.save({ pessimistic: true })` | |
cowboyd [12:09 PM] | |
So in terms of high level architecture patterns rather than code / libraries, we try to abide by the following. | |
1. form values only ever see a snapshot. If you’re using ember-data, this means you make a complete copy | |
2. updates happen transactionally in a single method. I think this echoes @mmun’s statement. If your update (or create) succeeds the snapshot is updated | |
willrax [12:09 PM] | |
we’ve been using ember-changeset to get something like this | |
samselikoff [12:10 PM] | |
charles how are you making copies of ember data models? have you done it with relationship graphs | |
mmun [12:10 PM] | |
this issue I find with ember-data is that you have to actually mutate a model in order to save it. so while the request is in-flight, your app can be in a confusing looking state. Of course there are ways to work around this but they are cumbersome. (edited) | |
cowboyd [12:10 PM] | |
This is getting into implementation details, but we have a “pull” model. | |
[12:11] | |
basically, we have form and field components | |
locks [12:12 PM] | |
Don't look at poupapp.com's forms | |
[12:12] | |
So, this might be too early but, fastboot enabled forms? | |
cowboyd [12:12 PM] | |
if you have a field like `{{x-field attr="foo"}}` | |
[12:12] | |
then you know to “pull” the `foo` attribute from the source object onto the snapshot | |
[12:12] | |
otherwise, if there’s no field for it, you don’t care | |
cherewaty [12:13 PM] | |
joined #topic-forms by invitation from @cowboyd | |
mmun [12:13 PM] | |
what is `model.save({ pessimistic: true })`? a custom adapter thing? (edited) | |
samselikoff [12:14 PM] | |
just a suggestion | |
mmun [12:14 PM] | |
o | |
samselikoff [12:14 PM] | |
no suggested api, that would only push changes into model after confirm from server | |
[12:14] | |
sorry. Only mark it as saved | |
[12:15] | |
not sure how it would work. Anyway | |
[12:15] | |
Interesting charles. I like the idea of snapshots/draft models, I think they solve a lot of problems | |
[12:15] | |
(in the past i've used draft models) | |
[12:16] | |
As far as the EmberMap series we're making, it's tackling a bit of a different aspect of the problem | |
mmun [12:17 PM] | |
I think @runspired is interested in supporting forking at the individual model level (edited) | |
samselikoff [12:17 PM] | |
would be great. I've basically hacked this in | |
[12:17] | |
DraftPost = Post.extend | |
[12:17] | |
then customize the adapter to still point to `/posts`. But your drafts have all the methods/CPs your model does | |
mmun [12:17 PM] | |
do you change the adapter type to be `post`? | |
[12:17] | |
yeah | |
[12:17] | |
that makes a lot of sense | |
samselikoff [12:18 PM] | |
exactly. Then if you save a `DraftPost` and, in adapter you say, if its successful `store.push('post', draft_post_id, draft_post_attrs)` | |
[12:18] | |
it works really well, relationships are hard. | |
mmun [12:19 PM] | |
do you have an example of the adapter code for that? | |
samselikoff [12:19 PM] | |
ya, sec | |
mmun [12:19 PM] | |
seems like a good workaround for most of my cases | |
samselikoff [12:20 PM] | |
wanted to extract it but didn't so it might be specific | |
[12:20] | |
yah its really nice | |
mmun [12:20 PM] | |
I think it’s too complicated to expect beginners to be able to do this | |
samselikoff [12:22 PM] | |
definitely. need to make an addon | |
[12:26] | |
@mmun https://gist.github.com/samselikoff/87cdf2db35ca8002cf38c4b7cf7df92d | |
mmun [12:27 PM] | |
ah, more than i expected | |
[12:27] | |
thanks | |
machty [12:27 PM] | |
it megasucks that this convo is going to be archived | |
locks [12:27 PM] | |
discuss thread? ;x | |
[12:27] | |
we want turn on the discourse slack integration, but I can't | |
samselikoff [12:27 PM] | |
To use, say you have a `lesson` from a route's `model` hook. Then you could pass `lesson` into a `{{lesson-form}}`. The form could then `lesson.createDraft()` and pass that around to all the inputs. When the form calls `draft.save()`, upon completion the adapter layer rolls the successfully-persisted changes back into the original `lesson` model. | |
runspired [12:28 PM] | |
joined #topic-forms by invitation from @mmun | |
locks [12:28 PM] | |
(I think it enables you to say "make a thread starting with X") | |
cowboyd [12:28 PM] | |
@samselikoff with the pull approach, you don’t need to proactively create a draft, and it works for all object types | |
[12:29] | |
that said, the draft api is still super useful inside the actual update transaction since you can contain the effects of the update from the rest of your application until you’re sure the transaction fully succeeded or failed. | |
samselikoff [12:29 PM] | |
right | |
[12:29] | |
I would love to go through details of your implementation some time | |
[12:30] | |
So back to the video series we're making. Again I think a lot of what we're talking about here is beyond the scope of what we're making | |
[12:30] | |
But we've seen some patterns come up in consulting clients and on slack so we wanted to talk about, data down actions up across different types of forms/components in an app | |
mmun [12:31 PM] | |
that’s exactly why the draft pattern is appealing to me. it just sucks that it requires so much boilerplate in the adapter. you also probably need a Lesson -> DraftLesson cloner. | |
samselikoff [12:31 PM] | |
Basically have seen something like this or a varient of it in a lot of places: | |
```{{blog-post-form | |
title=post.title | |
content=post.content | |
on-save=(action 'handleSave') | |
on-cancel=(action 'handleCancel')}} | |
``` | |
[12:31] | |
mmun check out the gist. The cloner is super simple in this case | |
[12:32] | |
and I had other methods to clone different models & set up some relationships sometimes | |
[12:32] | |
So, about the ^ snippet. I think some folks learned about DDAU and have been using it almost ritualistically across their entire application | |
[12:33] | |
but DDAU came about to help make data flow easier to reason about | |
[12:33] | |
The problem with the interface above is, a `blog-post-form` isn't a dumb reusable component, like a datepicker is | |
[12:34] | |
you would never write | |
```{{blog-post-form | |
title=post1.title | |
content=post2.content}} | |
``` | |
cowboyd [12:34 PM] | |
We tend to use pure-data components to model forms, that way they can be layered onto anything. | |
samselikoff [12:35 PM] | |
I think in some cases, the pendulum has swung too far, and people are too focused on not violating data down actions up that leads them to overabstract | |
mmun [12:35 PM] | |
@samselikoff: to be precise, `post` there would need to be a draft post, right? | |
samselikoff [12:35 PM] | |
(@mmun yes - but again i'm kinda tlaking about something different/more simpler than the draft case) | |
[12:35] | |
i'm making a more general point | |
[12:36] | |
or arguing a general point anyway. | |
mmun [12:36 PM] | |
towards a generic form builder? | |
samselikoff [12:36 PM] | |
For example, one-way bound `{{input value=val on-change=(mut val)}}` | |
[12:36] | |
(no - even simpler) | |
[12:36] | |
versus `{{input value=val}}` two-way bound | |
[12:37] | |
Ive worked with devs/teams that have basically lost hte ability to think through these situations, because they are so focused on not violating DDAU with every line of code | |
mmun [12:37 PM] | |
ah, you’re saying 2wb is fine if its effects are constrained? | |
samselikoff [12:37 PM] | |
yes | |
[12:38] | |
I think form debt comes in a lot of flavors | |
mmun [12:38 PM] | |
yeah, the whole core team agrees with you there. that’s the motivation for the `mut` “experiment” :stuck_out_tongue: (edited) | |
samselikoff [12:38 PM] | |
There's a class of hard problems like the ones we've been talking about so far | |
[12:38] | |
drafts, saving relationship graphs, optimistic vs. pessimistic saves | |
[12:38] | |
I think this is really hard and all the libs (changesets) and dif approaches (charles pull, draftable) are good and we need to move fwd on | |
[12:39] | |
But another class of form debt I've seen with consulting clients & beginners, is | |
[12:39] | |
folks that use ddau to make their forms pure and side-effect free. Which leads to passing models or attrs layers and layers down, only to send the action from the form layers and layers up | |
[12:39] | |
They try to decouple their form from its side effects in the name of ddau | |
[12:40] | |
But ddau was created because, some controls (like datepicker) have unpredictable side effects | |
[12:40] | |
In the case of a `blog-post-form`, you're making that form _precisely for_ its side effects (edited) | |
[12:40] | |
and your attempts to make it decoupled, end up spilling over layers of your application | |
cowboyd [12:40 PM] | |
I’m not seeing why those side effects can’t be contained inside actions. | |
samselikoff [12:40 PM] | |
So i think this is a misunderstanding of the role of services/ model layer in an ember app | |
mmun [12:41 PM] | |
i think i’m gonna need an example | |
[12:41] | |
:dizzy_face: | |
samselikoff [12:41 PM] | |
I think the simplest example is `{{input value=val on-change=(mut val)}}` vs `{{input value=val}}` | |
[12:41] | |
that's the absolute simplest example | |
mmun [12:42 PM] | |
but that doesn’t leak outside of the template layer, so i don’t think there is an important difference there. (edited) | |
ryanlabouve [12:42 PM] | |
joined #topic-forms | |
samselikoff [12:42 PM] | |
(assume first input is one-way bound | |
locks [12:42 PM] | |
you know what is one-way bound? native inputs :X | |
samselikoff [12:42 PM] | |
doesn't leak outside template, ok. But point is | |
[12:43] | |
But it is different in the sense that the latter violates ddau | |
[12:43] | |
In some form | |
[12:43] | |
(from perspective of many people) | |
[12:43] | |
and therefore basically disqualifies it from use | |
[12:43] | |
(just run with me for a sec) | |
[12:43] | |
So, people see `{{input val=val}}`, and their reaction is, "two-way bindings, side effects, bad" | |
[12:44] | |
so they `<input value={{val}} on-change={{action (mut val)}}>` | |
[12:44] | |
Ok so what would you say to that | |
[12:44] | |
if you were teaching someone, and they said that and then replaced the `{{input` helper with ^ that line | |
[12:45] | |
Anyone? :stuck_out_tongue: | |
cowboyd [12:46 PM] | |
At first blush, I’d actually prefer the long form, because it identifies work that you need to do. | |
[12:46] | |
`{{input val=val}}` sweeps that work under the rug | |
locks [12:46 PM] | |
I have an answer, deprecate `{{input}}` :P | |
samselikoff [12:47 PM] | |
woof. Ok maybe we have genuine disagreement here | |
[12:47] | |
> it identifies work that you need to do | |
could you elaborate? | |
cowboyd [12:47 PM] | |
Not sure if I disagree yet, but I think you’ve hit on a very interesting question here. | |
locks [12:47 PM] | |
I semi-agree with @cowboyd | |
[12:48] | |
another phrasing of it is "use the platform" | |
samselikoff [12:48 PM] | |
ok so, let me explain my thinking here | |
[12:48] | |
So if I was working with a beginner | |
[12:48] | |
or mentoring a team | |
[12:49] | |
and they submitted PR with ^ that change, bc they had read about ddau and wanted to use one-way data flow | |
[12:49] | |
I would say something like: one-way data flow does help us reason about our app, when data is moving all over the place | |
[12:49] | |
But here, what's the expected side effect of this input? What is hte purpose | |
[12:50] | |
`on-change` is an open door that we can configure, when we cnanot predict what should happen when an input field changes | |
[12:50] | |
But a super common use case of using `<inputs>` is to modify data | |
[12:50] | |
This is why `{{input}}` helper exists. It's common enough that it's included in Ember ot make you more productive | |
cowboyd [12:51 PM] | |
> it identifies work that you need to do | |
It is my experience that using actions with one-way binding scales with forms as they become more complex, two-way binding does not. So if you start with the scalable approach, you can well, scale it. Start with the dead end and you’re bound to crash into it. | |
abuiles [12:51 PM] | |
joined #topic-forms | |
samselikoff [12:51 PM] | |
When I'm reading a template, `<input value={{val}} on-change={{action (mut val)}}>` tells me I should not make assumptions about what's happening, I need to look at the value and the side effect | |
locks [12:52 PM] | |
I think that's what @cowboyd means. | |
samselikoff | |
`on-change` is an open door that we can configure, when we cnanot predict what should happen when an input field changes | |
Posted in #topic-formsToday at 12:50 PM | |
[12:52] | |
right, because it's explicit | |
samselikoff [12:52 PM] | |
Right but, I would counter with YAGNI | |
[12:52] | |
so say you start with `{{input value=value}}` | |
[12:52] | |
You use that for 9 fields on your form | |
locks [12:52 PM] | |
is actually serious about deprecating `{{input}}` (edited) | |
mmun [12:52 PM] | |
so what’d like to see is something like | |
```<input value={{val}}> | |
<input value={{bind val}}> | |
<input value={{val}} oninput={{updateValWithDebounce}}> | |
``` | |
samselikoff [12:52 PM] | |
then you add a 10th that needs to do an autocomplete AJAX fetch | |
[12:53] | |
ok so, noobie/2-way-binding only person here would do something like | |
[12:53] | |
make an observer, trigger side effect, etc... | |
[12:53] | |
Which we all agree is the wrong approach | |
[12:53] | |
At this point, `{{input}}` is not appropriate because your input helper is no longer "just mutating" the data | |
[12:54] | |
at this point you have more complex data flow, and so you'd want to switch to `<input on-change={{action 'fetchResultsAndSet'}}>` | |
ryanto [12:54 PM] | |
@mmun i like this, {{bind val}} would be current {{input}} helper today? | |
locks [12:54 PM] | |
except people then do `{{input value=value on-change={{action 'fetchResultsAndSet'}}` and then complain that Ember sucks :X | |
mmun [12:55 PM] | |
yes, it’s just a terser form of what sam wrote above (edited) | |
locks [12:55 PM] | |
@samselikoff my problem with this is my problem with most nuance | |
samselikoff [12:55 PM] | |
(i like that api too mmun) | |
mmun [12:55 PM] | |
I would be embarrassed to ever write `<input value={{val}} oninput={{action (mut val)}}>`. I think it is fine in spirit. Just syntactically gnarly. (edited) | |
locks [12:55 PM] | |
it's that people don't do nuance | |
samselikoff [12:55 PM] | |
@mmun me too - but people do that | |
locks [12:56 PM] | |
I don't see a problem | |
samselikoff [12:56 PM] | |
@locks in my experience working with teams cargo-culting ddau will get you into just as much trouble. People need to learn to use the primtives that Ember provides | |
[12:56] | |
dhh has said similar things about rails | |
[12:56] | |
that people need to learn how to use it. | |
igort [12:56 PM] | |
joined #topic-forms | |
locks [12:57 PM] | |
@mmun that won't actually work, will it ;P | |
samselikoff [12:57 PM] | |
An app I saw, you had to open 7 templates to change something. There's so much indirection and it was completely overwhelming for the engineer working on it | |
mmun [12:58 PM] | |
that really makes me sad. | |
samselikoff [12:58 PM] | |
Forms are fundamental to web apps and simple forms should not be overwhelming. Ember has a job here and `{{input}}` is a good abstraction. I think there's plenty of room for more good abstractions | |
mmun [12:58 PM] | |
I dislike when people create multiple one-off components to split up a template (like partials) | |
[12:59] | |
but then end up passing each component many attributes | |
samselikoff [12:59 PM] | |
So I think when it comes to things like implementing charles' pull method, or drafts, etc. ddau is perfect for those details. Make those abstractions much easier to build | |
[12:59] | |
yes mmun this is exactly it | |
mmun [12:59 PM] | |
I can see why people do it. There’s a trade off. | |
locks [1:00 PM] | |
I want to remember folk that the working version is `<input value={{appName}} oninput={{action (mut appName) value="target.value"}}>`, and it's beautiful | |
mmun [1:00 PM] | |
I just prefer locality over compartmentalization | |
samselikoff [1:00 PM] | |
right - but sometimes people split up components and pass in models thinking they're "ddau" | |
[1:00] | |
when all the models are referencing the same singleton instance from teh store | |
[1:00] | |
and end up creating lots of indirection. I've seen this a lot | |
cowboyd [1:01 PM] | |
runs off to grab some lunch. | |
samselikoff [1:01 PM] | |
lol locks. It is not | |
mmun [1:01 PM] | |
I try to keep my contexts as shallow as I can. This usually involves {{yield}}ing heavily. (edited) | |
machty [1:01 PM] | |
@locks that is beautiful only so much as some other higher level abstraction/syntax decomposes into that | |
[1:02] | |
if all of Ember higher level APIs decomposed in that way i'd be a much happier person | |
locks [1:02 PM] | |
you all need to #usetheplatform | |
samselikoff [1:02 PM] | |
no. Ember is about making us productive and happy | |
[1:02] | |
Ember should use the platform, not me | |
mmun [1:03 PM] | |
I agree that nice primitives are beautiful. so is sugar | |
locks [1:03 PM] | |
we just need sugar for `{{action (mut appName) value="target.value"}}`, like @mmun suggested | |
mmun [1:04 PM] | |
y not target.checked? | |
[1:04] | |
it’s tricky | |
[1:04] | |
each component would need to describe it’s default mutating mechanism | |
locks [1:04 PM] | |
@mmun not following | |
[1:05] | |
I'm talking about `<input>` | |
mmun [1:05 PM] | |
yes | |
[1:05] | |
```<input type="text" value={{val}} oninput={{action (mut val) value="target.value"}}> | |
<input type="checkbox" checked={{val}} onchange={{action (mut val) value="target.checked"}}> | |
``` | |
locks [1:06 PM] | |
we can sugar that | |
mmun [1:06 PM] | |
it’s not really possible to have a one-size-fits-all strategy because different properties trigger different events | |
[1:06] | |
but we can do it on a case-by-case basis. | |
locks [1:06 PM] | |
we get the event in the event handler | |
mmun [1:07 PM] | |
ideally when you write `checked={{bind val}}` it would ask the component… hey, what does it mean to bind to checked? | |
[1:07] | |
and we can provide a set of defaults for <input> (edited) | |
samselikoff [1:08 PM] | |
oh. that sounds really nice | |
ryanto [1:09 PM] | |
something that i think about with my forms is reusability. with `{{date-picker}}` i want DDAU because it gets used it so many difference scenarios, so side effects need to be decoupled for the component and defined by the caller with actions. but with `{{blog-post-form}}` its not really reusable. im only writing this component to update a blog post, so internally the component can make more assumptions since its side effects are focused. im ok with if `{{blog-post-form}}` is doing things internally like creating drafts, model mutations, and saves. | |
mmun [1:09 PM] | |
but if you wanted something non-default you could go back to: | |
```<input type="text" value={{val}} onkeydown={{action (mut val) value="target.value"}}> | |
``` | |
(edited) | |
locks [1:09 PM] | |
@mmun :ok_hand: | |
mmun [1:10 PM] | |
this was literally the design of {{mut}}. it just didn’t quite end up there. | |
locks [1:10 PM] | |
seeing people extending input classes is no bueno | |
mmun [1:11 PM] | |
@locks: Do you know why we don’t deprecate {{input}}? There is a blocker to even beginning to consider it. It is event delegation. (edited) | |
locks [1:12 PM] | |
I don't but I'm sure I'll learn when I start to write the rfc ;P | |
[1:12] | |
ttm | |
mmun [1:12 PM] | |
tbh I don’t fully understand but there are several people that do. | |
[1:13] | |
I just thought you should know before you push it too hard :slightly_smiling_face: the tl;dr is that if you use `element.onclick = function() { … }` naively the way we are you lose some of the determinism that we have with today’s event system (edited) | |
locks [1:13 PM] | |
gotcha | |
mmun [1:13 PM] | |
kris, stef, maybe rob, yehuda, maybe runspired | |
samselikoff [1:14 PM] | |
you guys have taken us off the :railway_track: | |
[1:14] | |
:stuck_out_tongue: | |
mmun [1:14 PM] | |
sorry, i’m done | |
samselikoff [1:14 PM] | |
go hang out in ember-dev why dontya | |
mmun [1:14 PM] | |
and sorry @ryanto | |
[1:14] | |
https://embercommunity.slack.com/archives/topic-forms/p1484330946000260 | |
ryanto | |
something that i think about with my forms is reusability. with `{{date-picker}}` i want DDAU because it gets used it so many difference scenarios, so side effects need to be decoupled for the component and defined by the caller with actions. but with `{{blog-post-form}}` its not really reusable. im only writing this component to update a blog post, so internally the component can make more assumptions since its side effects are focused. im ok with if `{{blog-post-form}}` is doing things internally Show more… | |
Posted in #topic-formsToday at 1:09 PM | |
locks [1:14 PM] | |
I don't know this mmun person. | |
runspired [1:14 PM] | |
I understand :stuck_out_tongue: | |
samselikoff [1:14 PM] | |
i kid :stuck_out_tongue: anyways, {{bind val}} is the same as {{input}} from my perspective | |
[1:14] | |
and it is good (edited) | |
[1:14] | |
basically it's ryans point ^ | |
runspired [1:15 PM] | |
I want to RFC a new event system (to replace my existing RFC as that one was incomplete) | |
samselikoff [1:15 PM] | |
I think this is lost on lots of people who hear/learn ddau and run with it to the extreme | |
locks [1:16 PM] | |
cargo culting is weird | |
[1:16] | |
like, Ember is inherently 2wb | |
ryanto [1:19 PM] | |
i guess my argument about `{{date-picker}}` and `{{blog-post-form}}` is that when we learn `{{date-picker}}` we learn that DDAU is the right way to do things, which leads to an incorrect design of `{{blog-post-form}}`. For example when I see `{{blog-post-form on-attribute-change=(action "…") on-save=(action "…") on-reset=(action "…")}}` it makes me think DDAU has gone too far since these types of side effects should be defined inside of the form components.... since you know, they’re form related. im not sure everyone agrees with this statement though. | |
locks [1:20 PM] | |
hhmm | |
[1:20] | |
this discussion is kinda hard without more code in front of us | |
[1:20] | |
I agree that it's a code smell | |
[1:22] | |
having too many bindings is usually a warning to look at your architecture | |
ryanto [1:23 PM] | |
ok let me try to come up with an example, i would say `{{date-picker model=model}}` is bad. we dont know the models date attribute, we make too many assumptions, and this leads to pure pain. so we get to `{{date-picker date=model.date on-change=(action (mut model.date))}}` | |
samselikoff [1:23 PM] | |
yep, agree. The way i’ve heard it said is “two-way bindings aren’t bad. using two-way bindings as a message bus is bad." | |
locks [1:23 PM] | |
for future reference, assume I'm mostly taking the perspective of a newbie as I envision | |
samselikoff [1:24 PM] | |
yep | |
ryanto [1:24 PM] | |
but with `{{blog-post-form model=model}}` is fine. because blog-post-form is specific to our application, its working in our domain, we can make a ton of assumptions. | |
samselikoff [1:26 PM] | |
yes. There’s a relationship between DDAU and what you can assume about the side effects of a component or form | |
ryanto [1:30 PM] | |
i think ddau makes blog-post-form worse off, because when you have `{{blog-post-form model=model on-save=(action "savePost")}}` you now have to know about two components in order to understand this form. you need to look at `blog-post-form` component and the parent where the `savePost` action is defined. i think this indirection makes it harder to understand. so i like to question if we need the explicit action for the side effect… for `{{date-picker}}` the answer is 100% yes, but for the blog-post-form im not sure we do. (edited) | |
locks [1:35 PM] | |
@ryanto I feel like there's a bigger discussion here, wrt `on-save` | |
[1:36] | |
mainly because you're passing `model` in | |
[1:36] | |
so I'm assuming this comes from `model()` | |
ryanto [1:36 PM] | |
well lets say we didnt pass model in | |
locks [1:36 PM] | |
unlike say a self-contained search box | |
[1:37] | |
:thinking_face: | |
ryanto [1:37 PM] | |
what if we had `{{blog-post-form title=model.title on-save=(action "savePost")}}` | |
locks [1:37 PM] | |
I'm assuming save + transition inside the component? | |
ryanto [1:38 PM] | |
i would say this component is pure ddau, but poor interface since blog-post-form should know how to do both those things (get title and perform save) (edited) | |
[1:40] | |
i would say… yes save, transitions, or whatever a developer expects when you click the save button would live inside of the component. they would only move outside of the component if they needed to be configurable (in other words different use cases). | |
locks [1:43 PM] | |
hm | |
[1:43] | |
I'm not too fond of the transition inside | |
samselikoff [1:44 PM] | |
But at least you’re arguing on the margin. Main thing we want our video series to communicate is, folks should approach building forms the same way they build other pieces of their application: build it to the specific use-case first, and only abstract/expose new APIs as they are needed (YAGNI). | |
ryanto [1:44 PM] | |
sure - me too, but its not about the transition, its about expectation | |
samselikoff [1:45 PM] | |
The thing is with reusable components or addons, you want to use pure ddau, because you’re by definition building for a general use case. But a `blog-post-form` is an application feature | |
ryanto [1:45 PM] | |
if every time i save a blog post i transition to that posts route, why bother doing `{{blog-post-form model=model after-save=(transition-to "post" model)}}` | |
[1:47] | |
im trying to think of ways to phrase this argument, its the idea that theres a tradeoff between DDAU and increased api/configurability. | |
locks [1:48 PM] | |
I'm also trying to find the words for what I want to say xD | |
samselikoff [1:48 PM] | |
say “I love the {{input}} helper" | |
[1:48] | |
:stuck_out_tongue: i kid | |
ryanto [1:49 PM] | |
i think with components we can ask what their reusability is, and if its “a lot!” then ddau makes a ton of sense. so `{{date-picker}}` you want a nice api/configurability via actions and props | |
[1:50] | |
but {{edit-customer-profile-form}} isnt likely to be reused, this component isnt going to be an addon, and good luck using it outside my application. so we can sacrifice ddua for concise api, only passing in a model | |
locks [1:51 PM] | |
`blog-post-form` is both for creating and updating a blog? | |
samselikoff [1:51 PM] | |
and its not just losing ddau for no gain. Now when you make a change, you look in one place instead of everywhere | |
new messages | |
locks [1:52 PM] | |
I think I know were our disagreement is, if only I were going to emberconf :sob: | |
ryanto [1:52 PM] | |
locks, sure- lets say yes. in that case i think we can say since it does both create and update it should have an `after-save=(action "…")` since the after save for create would be different from update. but we only add this feature at this point, not when were creating the component (edited) | |
ryanto [1:54 PM] | |
ok i think this gets at my argument. i would say maybe, but for most forms create and update are something like `validate()` and `save()`. so it can be built into the form, not an outside action | |
[1:54] | |
and of course, if you have different create/save logic then you can make it an outside action, or different component actions, but the point is you dont do that until you need it. | |
[1:56] | |
btw im talking a lot of ideas/concepts here… i think my argument for all this comes off seeing real world ember apps that have form components that take 12 properties and 6 actions in order to not allow the component to have any side effects. often seeing these passed down 2-3 template layers too (edited) | |
[1:58] | |
the refactor we always do is turning that side effect free form into a “smart component”. this is the term we’ve been using for a component that “does it all”. often leads to easier component (from both the callers perspective and the internal component itself). | |
[2:00] | |
usually it goes something like… blog-post-form component with side effects and that component uses a bunch of side effect free addons (date pickers, etc). nice balance of reusable smaller pieces but a specific place (blog-post-form) for the developer to put application and expected side effects. rather than bubbles these all up to the route/controller. (edited) | |
[2:02] | |
ok im done :slightly_smiling_face: but would love to hear if people generally agree/disagree with this (edited) | |
machty [2:03 PM] | |
parsing | |
locks [2:04 PM] | |
@ryanto did you mean easier composition | |
[2:05] | |
what I'm hearing is that blog-post-form is your route template :joy: | |
[2:05] | |
sounds like a container component (react literature) | |
ryanto [2:07 PM] | |
im not familiar with container components, but the form components can be at any level. sometimes nested 2-3 levels deep | |
locks [2:08 PM] | |
https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0 | |
Medium | |
Presentational and Container Components | |
You’ll find your components much easier to reuse and reason about if you divide them into two categories. | |
Reading time | |
---------------- | |
5 min read | |
(180KB) | |
March 23rd, 2015 at 7:23 AM | |
[2:08] | |
container -> self-contained | |
presentational -> ddau | |
ryanto [2:09 PM] | |
exactly | |
[2:10] | |
yes- agree. so similar to a container component having access to flux actions, i think a form component should have access to `model.save()` or `model.set()` | |
[2:11] | |
and not be looked at as this violates ddau | |
locks [2:11 PM] | |
semantically there's nothing above it to get dd from and au to :P | |
josh.hollinshead [2:24 PM] | |
joined #topic-forms | |
ryanto [2:26 PM] | |
btw forms are hard :slightly_smiling_face: i feel like i steered the topic to component design/api, but theres so much more in terms of drafts+ saving strategies, client/server validations, slow internet… (edited) | |
samselikoff [2:29 PM] | |
i think I would say that ddau came about to address complex and unpredictable side effects (bindings that trigger multiple things simultaneously). but when side effects are well-understood and predictable (like they tend to be for many domain-specific application components) some aspects of ddau become premature abstraction | |
[2:30] | |
and in those situations 2wb and Ember primitives like {{input}} should be embraced, because they are familiar to ember devs and keep you productive | |
machty [2:59 PM] | |
man i've been so backed up w prod issues today | |
[2:59] | |
i blame forms | |
[2:59] | |
but i promise to chime in shortly | |
kyle [3:37 PM] | |
joined #topic-forms | |
machty [3:46 PM] | |
more important than strict DDAU is clear ownership of data that doesn't sneakily / subtly / destructively bleed out into the rest of the app | |
machty [3:56 PM] | |
i think i just echoed @samselikoff | |
kyle [4:22 PM] | |
So why {{blog-post-form}} and not reusable form component(s) that yield out? This works pretty well for us - we keep as much as we can at route template level. | |
samselikoff [4:24 PM] | |
@machty exactly. proper separation of concerns. How easy is it to change your forms and components that deal with your primary application data? If you add a field to a model, do you have ot change components and templates in 7 places? | |
[4:25] | |
@kyle I would say if you have a route that is basically just a form, then yes you could start by not even using a form component, and doing everything in the route/controller/template. After all, those three objects already exist, and if thats their only job, start with that. If you don’t need a separate component, don’t make it. Yagni | |
[4:26] | |
But what if you’re making an app like Trello? Homepage route has quite a lot going on. So you’ll probably end making a {{trello-card-form}}, an {{add-members-form}}, a {{side-bar}} component and so on | |
samselikoff [4:36 PM] | |
Also what I’ve found working with teams is, its really nice to establish some conventions. So if every app you have, every time you have a form where your editing data, its always a `{{some-model-name-form}}`, the `tagName` is always form, and component does validations and saving, and delegates to the outer template only when its behavior needs to be customized | |
[4:37] | |
Establishing these patterns is really nice | |
[4:37] | |
And I think a component like that, most ember developers could jump in and understand it quite easily. The form’s `<input type="submit">` calls a local action that performs `model.save()`. Bread-and-butter stuff | |
kyle [4:46 PM] | |
@samselikoff yeah if you have a complex route with multiple forms or a single form multiple times. in these situations we have wrapper form components that repurpose our generic form component, but theyre pretty lightweight | |
[4:47] | |
not an overly common situation for us though, most of the time we’re aiming to architect ui for single form per page and question hard if the ui really needs mulitple forms | |
[4:48] | |
cases like trello dashboard are defo a yes | |
samselikoff [4:48 PM] | |
any chance I could see an example of a dedicated form page? Curious to gather examples as we make this video series | |
[4:48] | |
trello, yah. (edited) | |
[4:48] | |
(example code) | |
kyle [4:49 PM] | |
sure, will try grab something for you tomorrow if thats ok | |
ryanto [4:49 PM] | |
form component that wraps a generic form i think is good. it gives you a domain form component that can control side effects (edited) | |
[4:50] | |
like using `{{form-for}}` addon inside of `{{blog-post-form}}` | |
kyle [4:50 PM] | |
hang on - might have a snippet | |
[4:51] | |
```{{#ui-form as |form|}} | |
{{#form.title}} | |
Edit field | |
{{/form.title}} | |
{{#form.fieldset}} | |
{{#form.dropdown | |
options=contentFields | |
selected=changeset.contentField | |
onchange=(action (mut changeset.contentField)) | |
placeholder="Please select" | |
as |contentField| | |
}} | |
{{contentField.name}} | |
{{/form.dropdown}} | |
{{#form.field}} | |
{{form.text-field | |
id="name-field" | |
placeholder="Name" | |
label="Name" | |
value=changeset.name | |
required=true | |
}} | |
{{/form.field}} | |
{{/form.fieldset}} | |
{{#form.footer}} | |
{{ui-button | |
label="Confirm changes" | |
theme="good" | |
onclick=(route-action "confirm") | |
}} | |
{{ui-button | |
label="Delete" | |
theme="danger" | |
onclick=(route-action "delete") | |
}} | |
{{ui-button | |
label="Cancel" | |
theme="simple" | |
onclick=(route-action "cancel") | |
}} | |
{{/form.footer}} | |
{{/ui-form}}``` | |
(edited) | |
ryanto [4:53 PM] | |
is that a route template or component template? | |
kyle [4:53 PM] | |
route template | |
cowboyd [4:55 PM] | |
Have we talked about how all forms have form-level concerns? like whether it is submittable, whether it is submitting, whether its dirty, validation state and how all those play together every time? | |
[4:55] | |
also, diffs between current edits and the source object? | |
[4:55] | |
Don’t want to derail, but we’ve done some analysis on this and are trying to capture it in a pure js library https://github.com/cowboyd/form-x | |
[4:56] | |
I’d be curious to get some feedback. I think it’s beyond the scope of where the conversation started | |
ryanto [4:57 PM] | |
kyle makes sense, and i think if ever needed you can turn that into a form component, but as is thats very readable. i think our discussion is about what does it look like if that does become its own component. | |
cowboyd [4:57 PM] | |
but wanted to mention it at some point. | |
ryanto [4:57 PM] | |
cowboyd we havent, im of the opinion that the form should know how to do all those things 99% of the time. | |
cowboyd [4:58 PM] | |
Yeah, thats kinda the conclusion we’ve come to, and tried to map out, just what those things are. | |
[4:58] | |
because they seem intertwined. | |
kyle [4:58 PM] | |
@ryanto yeah in places where we need a reusable form, we repackage inside a dedicated component and then ddau (edited) | |
kyle [5:06 PM] | |
form-x looks really interesting | |
cowboyd [5:09 PM] | |
@kyle lemme know what you think. We’re just trying to capture all form concerns in a single place. | |
kyle [5:10 PM] | |
does it currently handle dirty values? (edited) | |
[5:11] | |
ah yes - see it in the form object | |
cowboyd [5:13 PM] | |
it will, yes. We haven’t actually written the Form class in practice though | |
kyle [5:14 PM] | |
ok cool, looks great | |
[5:15] | |
plans to handle relationship dirtying? | |
cowboyd [5:20 PM] | |
What is relationship dirtying? Like when a related object changes? | |
machty [5:22 PM] | |
hey, potential de-railment, again, but I wanted to share a new pattern i've discovered that relates to building configurable/composable APIs, that I think may very well likely impact our thinking about the ideal form API: https://ember-twiddle.com/d51ce8adf3870c771a1bbe0b12c0776f?numColumns=2&openFiles=templates.application.hbs | |
.... | |
runspired [3:22 AM] | |
I have been sold on same file | |
[3:22] | |
But I'm less convinced they should be unified | |
[3:22] | |
I am however in favor of more powerful templates | |
[3:22] | |
I personally have started viewing component.js as a reducer / store | |
[3:23] | |
And the template as the component | |
[3:23] | |
Cc @cowboyd @machty | |
swastik [8:45 AM] | |
joined #topic-forms | |
machty [9:57 AM] | |
@runspired would be curious for what that looks like | |
[9:57] | |
can't tell if i already write code that way or what | |
cowboyd [11:49 AM] | |
That’s very similar to how I’ve come to think about it. Whether it’s using a component or a helper to contain state. | |
[11:51] | |
There are still cases where the cleanest way to compose things would be the ability to perform “reductions” inside the template. | |
[11:51] | |
and to do that, you need to be able to define lambda abstractions inside hbs (I think) | |
[11:52] | |
Let me see if I can come up with an example | |
machty [11:52 AM] | |
we have lambda abstractions but only with template blocks of html | |
[11:53] | |
you can't do `{{#each (map items (|i| i.wat)) as |wat|}}...` | |
cowboyd [11:53 AM] | |
right, so here’s where we ran up agains this limitation | |
[11:54] | |
and you hit the nail on the head btw | |
[11:56] | |
I think you may have even seen this. We had a file upload component that was fantastic. It kept all the upload state and then presented the current state to the template via a yielded parameter. `upload.progressPercentage`, `upload.isComplete`, etc… That was awesome..... until we wanted to track mulitple uploads concurrently. | |
[11:57] | |
because we need to reduce all of the uploads into a single aggregate state. i.e. reduce | |
[11:58] | |
a pretty simple reduction in any language, right? in js it would be like `uploads.any(upload => upload.isPending)` | |
[11:58] | |
I guess that would be `some` | |
machty [12:01 PM] | |
so you had something that presumably started off as an object/task on the component and you had to split that out into separate objects (edited) | |
[12:02] | |
was this the example where yall had these objects that were really just dressed up tasks? | |
cowboyd [12:02 PM] | |
p much. | |
[12:03] | |
would really like o be able to say: `{{any uploads (fn [u] u.isPending}}` | |
machty [12:07 PM] | |
yeah | |
[12:07] | |
you'd have to delegate to a helper | |
cowboyd [12:07 PM] | |
or an action I guess | |
machty [12:08 PM] | |
`{{any uploads (is 'isPending'))}}` (edited) | |
[12:08] | |
`{{any uploads (is 'someMethod' arg1 arg2))}}` (edited) | |
[12:09] | |
(this last one extends it so that someMethod could be a property or some bool method that accepts multiple args) | |
[12:10] | |
(or the method returns a Reference that essentially tells glimmer that it'll handle invalidating over time rather than letting the helper API decide to recompute as inputs change) | |
cowboyd [12:11 PM] | |
Yeah, those are all pretty good solutions, and you could even write a syntax transform so that you could use symbols instead of strings. | |
[12:12] | |
although usually the refactoring workflow is first `{{any uploads (fn [u] u.isPending}}`, then `{{any uploads (is pending)}}` so not having the intermediary available trips up your thinking | |
[12:12] | |
The other case is where you want to decorate extended values via a map. | |
[12:13] | |
We actually wanted to do that as well, and tripped up. you alluded to it with your map. | |
[12:13] | |
`{{#each (map files (|f| file-upload f)) as |upload|}}` | |
[12:15] | |
`(|f|)` love that as a syntax for `λ` | |
machty [12:15 PM] | |
yeah it's not bad... | |
[12:16] | |
huh | |
[12:17] | |
yeah, kinda really like it too | |
cowboyd [12:17 PM] | |
You just come up with that in the moment? | |
machty [12:17 PM] | |
lol yeah i didn't think it was anything special | |
cowboyd [12:18 PM] | |
well, fwiw, I give it a +1 :slightly_smiling_face: | |
[12:19] | |
Actually I got that wrong: it should be `{{#each (map files (|f| (file-upload f))) as |upload|}}` since `file-upload` is a function/helper | |
[12:20] | |
Is there any way to do that today in ember with hackery / syntax tranforms? | |
machty [12:27 PM] | |
i dunno | |
[12:28] | |
maybe ask #dev-glimmer | |
[12:28] | |
would be curious to see what all you could do with it | |
cowboyd [12:35 PM] | |
Probably a good idea. | |
[12:35] | |
(for a weekday) | |
machty [12:35 PM] | |
is that how you do for loops in clojure | |
cowboyd [12:37 PM] | |
like how? | |
machty [12:37 PM] | |
i was making a bad joke: `(for a weekday)` | |
cowboyd [12:38 PM] | |
hahahahhaha. | |
[12:39] | |
you actually had me trying to re-write that `map` up there as a `for` comprehension | |
[12:40] | |
Someone needs to rename this channel #off-topic-forms :slightly_smiling_face: | |
machty [12:41 PM] | |
let's bring it back | |
mmun [1:04 PM] | |
yeah i want lambdas too | |
[1:04] | |
people will flip tables, but i want to try it | |
cowboyd [1:05 PM] | |
Well @machty did all the hard work by coming up with a syntax. | |
mmun [1:05 PM] | |
every time i have to make a js file for a component i feel i have lost | |
cowboyd [1:05 PM] | |
*yes* | |
mmun [1:05 PM] | |
(not really true, but kinda true) | |
machty [1:05 PM] | |
ember has too much "do i really have to" API | |
mmun [1:06 PM] | |
obviously there are imperative things that are just easier to do with js (i.e. tasks) | |
[1:06] | |
i also want block-lambdas | |
cowboyd [1:06 PM] | |
do tell. | |
mmun [1:07 PM] | |
basically lambdas whose result is a handlebars block | |
[1:07] | |
so that you can do `{{each items &block}}` | |
[1:07] | |
analogous to `items.each &block` | |
[1:08] | |
you can think of it as a regular lambda that generates DOM (edited) | |
cowboyd [1:08 PM] | |
How would captured blocks specefiy their parameters? | |
[1:09] | |
in theexplicit form `{{#each items as |item|}}` `item` is what’s bound. | |
mmun [1:09 PM] | |
sure | |
machty [1:09 PM] | |
(possibly syntax to avoid introducing another sigil `{{each items as block}}`) (edited) | |
mmun [1:09 PM] | |
```{{#let-block greeting as |person|}} {{person.name}} {{/let-block}} | |
{{each items &greeting}} | |
{{each items &greeting}} | |
``` | |
(edited) | |
[1:10] | |
^ not a good example for motivation. more of a tech demo. | |
[1:11] | |
the motivation would be to support drag-and-drop between two lists and not needing to rerender the item when it jumps from one list to the other | |
[1:11] | |
because we can statically determine that are rendered by the same block | |
machty [1:12 PM] | |
you could guarantee that by enforcing that all draggable things are defined in separate templates/components right? | |
mmun [1:13 PM] | |
yeah | |
machty [1:13 PM] | |
but i agree that i want that syntax as well | |
[1:13] | |
i see it as an alternative to the block slot syntax people want so bad | |
mmun [1:13 PM] | |
```{{#each items as |person|}} {{greeter person=person}} {{/each}} | |
{{#each items as |person|}} {{greeter person=person}} {{/each}} | |
``` | |
[1:13] | |
in theory we could see that those two blocks are the same | |
[1:14] | |
but feels hacky | |
cowboyd [1:14 PM] | |
I like it. Would also be nice to have a module system to share blocks. | |
mmun [1:14 PM] | |
@machty: yes it absolutely is | |
machty [1:14 PM] | |
```{{#let-block header as |person|}} {{person.name}} {{/let-block}} | |
{{#let-block footer as |person|}} {{person.name}} {{/let-block}} | |
{{#let-block wat as |person|}} {{person.name}} {{/let-block}} | |
{{complex-component header=header footer=footer wat=wat}} | |
``` | |
mmun [1:14 PM] | |
the problem, as i see it, is that it pulls the block away from where it is used | |
cowboyd [1:14 PM] | |
`{{import greeter="blocks/greeter"}}` | |
mmun [1:14 PM] | |
which kinda sucks | |
machty [1:15 PM] | |
i've given up on block slot syntax, which is both likely unsolvable and ultimately a subset of having local anonymous blocks | |
mmun [1:15 PM] | |
yeah, that’s the evolution i was getting at | |
[1:15] | |
to make them completely anoynmous | |
[1:16] | |
```{{complex-component | |
header=(|person| {{person.name}}) | |
footer=(|person| {{person.name}}) | |
wat=(|person| {{person.name}}) | |
}} | |
``` | |
[1:16] | |
:bike: :derelict_house_building: | |
machty [1:17 PM] | |
is that you riding your bike home away from this convo, or bikeshedding | |
mmun [1:17 PM] | |
derelict bike shed | |
[1:17] | |
i just mean that the syntax ^^ probably sucks. | |
machty [1:20 PM] | |
i want to avoid that bikeshed. can't imagine the solution along that path not looking like php (edited) | |
[1:21] | |
let's start with the assumption that you define the blocks at raw toplevel html level | |
mmun [1:21 PM] | |
fwiw, yehuda suggested it to me | |
[1:21] | |
named blocks are still useful as well, so seems ok to design them first (edited) | |
machty [1:22 PM] | |
is there a case where named blocks express something that can't be expressed w local anon blocks? | |
mmun [1:22 PM] | |
no | |
[1:22] | |
sry, got that reversed | |
[1:23] | |
named blocks allow you to reuse the same block and statically know that | |
[1:23] | |
that’s the only difference | |
machty [1:23 PM] | |
https://thefeedbackloop.xyz/stroustrups-rule-and-layering-over-time/ | |
The Feedback Loop | |
Stroustrup's Rule and Layering Over Time | |
Programming language experts like to claim that syntax doesn't matter, that semantics is all that counts. Don't believe them! They're overrotating on a common, pre-rigorous misunderstanding of language design as superficially aesthetic. The study of semantics does provide deep insights into the mechanics of languages—but the mechanism is not | |
Written by | |
---------------- | |
Dave Herman | |
Dec 16th at 2:53 AM | |
[1:23] | |
so do anonymous local blocks | |
mmun [1:24 PM] | |
yes, technically you’re right | |
[1:24] | |
you can do {{let blah=(anon block)}} (edited) | |
[1:25] | |
and arguably it would suck to have two ways to create blocks bound to variables | |
[1:25] | |
i.e. ` {{let blah=(anon block)}}` and `{{#let-block}}` | |
[1:26] | |
@cowboyd: have you ever felt this desire for first class blocks? | |
[1:27] | |
it becomes particularly apparent when you try to customize e.g. `power-select` | |
locks [1:27 PM] | |
Begging the question, sir :troll: | |
mmun [1:27 PM] | |
you are forced to pass in (component …) objects | |
cowboyd [1:27 PM] | |
Right, which means forcing a context switch. | |
mmun [1:27 PM] | |
i just hate having to create an extra tiny file (edited) | |
[1:28] | |
(the context switch!) | |
[1:28] | |
and also giving it a global name bugs me, though the module reform stuff has solutions for that particular issue (edited) | |
cowboyd [1:28 PM] | |
It also means it's harder for non-you to parse in 6 months (edited) | |
[1:28] | |
module reform? | |
mmun [1:29 PM] | |
dgeb’s big rfc | |
machty [1:29 PM] | |
good luck avoiding the global name and instead finding a syntax for inline that 1) makes sense 2) avoids ugly `{{ }}` stacking | |
locks [1:29 PM] | |
Module unification | |
[1:29] | |
You only have local and global lookup | |
mmun [1:29 PM] | |
@machty is that a genuine good luck or do you think it is a non-starter | |
[1:30] | |
:stuck_out_tongue: | |
machty [1:30 PM] | |
non-starter (edited) | |
[1:30] | |
sorry, that all came off super sarcastic. | |
[1:31] | |
i'm so sure it'll not work that i'm wary of all the bike-shedding that'd distract us away from the base primitives that would work great today | |
mmun [1:31 PM] | |
i don’t fully understand your position: what do you think is the best avenue to explore? | |
locks [1:31 PM] | |
I feel like this channel is what #topic-architecture should have been | |
[1:31] | |
Loving the discussions | |
machty [1:32 PM] | |
@locks yeah me too; it's a very nuanced kind of conversation that i've only been able to individually have with certain people and certain use cases. (edited) | |
cowboyd [1:32 PM] | |
btw, @mmun in clojure, `(defn name [x y])` is literally a macro for `(def name (fn [x y]))`, so I think having two forms, one expressed via the other is preferable. | |
[1:32] | |
rather than undesirable | |
mmun [1:32 PM] | |
@cowboyd: :+1: i appreciate your insights (edited) | |
locks [1:33 PM] | |
I hope you know I think this is vital, even if my answers are sometimes short | |
[1:33] | |
@cowboyd why not lisp? | |
mmun [1:34 PM] | |
@machty: is something #let-block-ish acceptable to you? | |
machty [1:34 PM] | |
```Primitive 1: define a local block and give it a local name. | |
(syntax open to bike-shedding) | |
{{#let-block foo as |person|}} {{person.name}} {{/let-block}} | |
Primitive 2: use that block anywhere you'd use `as |x|` | |
(syntax open to bike-shedding) | |
{{#each people as foo}} | |
In my mind, there is no third primitive. | |
We shouldn't add block slot syntax (for now at least). | |
Any component that desires block syntax can use the above primitives | |
to accept blocks as attrs. Note that proposed block syntax makes | |
it hard/impossible to use the same block in multiple places, whereas | |
the above primitives make it trivial | |
{{sample-component | |
slotName1=foo | |
slotName2=foo | |
slotName3=foo}} | |
``` | |
locks [1:34 PM] | |
I'm more asking if you've tried to wrangle cljs | |
machty [1:34 PM] | |
@mmun ^ answers the best avenue question | |
cowboyd [1:35 PM] | |
@locks cljs is a lot of fun. | |
[1:35] | |
But it doesn’t have anything near the maturity or scope of Ember | |
mmun [1:35 PM] | |
yeah, I’m not enthusiastic about slots. | |
locks [1:36 PM] | |
I mean for templating | |
[1:36] | |
Like emblem, I guess | |
mmun [1:36 PM] | |
if you use slots you start to get into weird situations | |
machty [1:36 PM] | |
@mmun it sounds like you still want some third thing like | |
```{{complex-component | |
header=(|person| {{person.name}}) | |
footer=(|person| {{person.name}}) | |
wat=(|person| {{person.name}}) | |
}} | |
``` | |
mmun [1:36 PM] | |
like… what if you want to define multiple columns for a table… you’d want an array of column blocks | |
machty [1:37 PM] | |
but that is reducible to the final block slot replacement example i gave | |
mmun [1:37 PM] | |
sure, I see it the other way around haha | |
[1:38] | |
feels awkward that the “reduction” involves introducing a hygenic name in the scope (edited) | |
[1:39] | |
but, ultimately, they’re almost exactly the same thing to me | |
[1:39] | |
if you’re on board with let-block, i can get behind that. | |
[1:40] | |
there’s no argument: the lambda syntax is a bikeshedding black hole | |
cowboyd [1:41 PM] | |
Another issue you might have that would want to drive you towards | |
```{{complex-component | |
header=(|person| {{person.name}}) | |
footer=(|person| {{person.name}}) | |
wat=(|person| {{person.name}}) | |
}} | |
``` | |
[1:41] | |
is that you want to preserve the “high-level” conceptual context | |
[1:41] | |
wich is that I’m rendering the `complex-component` | |
[1:42] | |
if you see 10 lines a bunch of `let-block` statements before you actually get to the business of rendering `complex-component` | |
[1:42] | |
then it can feel like “why?” untill there’s an “oooooooh" | |
[1:42] | |
One way that might make it feel better is to allow putting the named let-blocks _after_ where they are used. | |
[1:43] | |
This is one of my favorite things about haskell | |
locks [1:43 PM] | |
That sounds super bad | |
machty [1:43 PM] | |
```{{complex-component | |
header=(|person| hi i am raw dom text fragment {{person.name}} or am | |
I misunderstanding the proposed <span>syntax</span>. | |
Commence the infinite bikeshed. | |
) }} | |
``` | |
cowboyd [1:45 PM] | |
```{{complex-component header=personHeader}} | |
{{#where personHeader as |person|}} {{person.name}} {{/where}} | |
``` | |
mmun [1:46 PM] | |
@machty: it works for JSX | |
cowboyd [1:46 PM] | |
Still relies on names to wire them together, but perhaps addresses some of the “separation” you feel. | |
[1:46] | |
(I feel that too) | |
mmun [1:46 PM] | |
there’s gotta be _some_ way to execute it in hbs | |
[1:46] | |
but if you strongly feel it is a waste of time (like a distraction) i’m happy to punt (edited) | |
machty [1:46 PM] | |
it works for JSX because everything is assumed to be wrapped in a component | |
cowboyd [1:47 PM] | |
I agree that it feels like a infinite :black_circle:, but to leave it unsolved also feels like admitting a fundamental deficiency | |
machty [1:47 PM] | |
this is why i posted the Feedback Loop article on the Stroustrup whatever | |
[1:47] | |
```{{#let-block sharedHeader as |person|}} {{person.name}} {{/let-block}} | |
{{complex-component | |
header=sharedHeader}} | |
{{complex-component | |
header=sharedHeader}} | |
{{complex-component | |
header=sharedHeader}} | |
``` | |
[1:48] | |
^ we _know_ we want to support this | |
[1:48] | |
sharing an anon block between multiple complex-components | |
[1:48] | |
we should absolutely release this feature | |
mmun [1:48 PM] | |
yeah. cowbody convinced me with his clojure analogy | |
machty [1:48 PM] | |
and paralleledly/after the fact discuss an inline approach | |
[1:48] | |
i'm happy to hoist `let-block` defs so that order doesn't matter | |
mmun [1:50 PM] | |
i’d prefer not. less places to look | |
machty [1:50 PM] | |
lol "cowbody" | |
cowboyd [1:51 PM] | |
I know I haven’t worked out in months, but that’s pretty harsh man (edited) | |
machty [1:53 PM] | |
what's the syntax for yielding to a passed in block | |
[1:53] | |
like if complex-component wants to render header (and render a default if none specified) | |
mmun [1:54 PM] | |
today it is {{yield to=blah}} | |
[1:54] | |
where `blah=someNamedBlock` in the component invocation | |
[1:54] | |
glimmer more or less supports this internally. it’s just missing the let-block part to stash the block. but "block references” are a thing already. (edited) | |
cowboyd [1:54 PM] | |
you want something more like `{{yield &header}}`? (edited) | |
runspired [1:54 PM] | |
@locks we had these sorts of convos in #topic-architecture back in the day | |
locks [1:55 PM] | |
yeah | |
machty [1:55 PM] | |
maybe it's `{{yield a b c as namedBlock}}` | |
cowboyd [1:56 PM] | |
ah right that would be more principle of least suprisy. | |
machty [1:56 PM] | |
```{{#yield a0 b1 c2 as |a b c|}} | |
{{a}} {{b}} {{c}} | |
{{/yield}} | |
``` | |
runspired [1:56 PM] | |
have you looked at Vue’s slots? | |
machty [1:56 PM] | |
naw, link? | |
runspired [1:57 PM] | |
https://vuejs.org/v2/guide/components.html#Content-Distribution-with-Slots | |
vuejs.org | |
Components — Vue.js | |
Vue.js - Intuitive, Fast and Composable MVVM for building interactive interfaces. | |
mmun [1:57 PM] | |
i’m not convinced by `as`. feels more like a `to`? e.g. you yield to oncoming traffic | |
runspired [1:57 PM] | |
people are using them for higher order components in Vue | |
machty [1:58 PM] | |
@mmun seems fine, i'm just aiming for minimal syntax introduction and conceptual consistency | |
mmun [1:58 PM] | |
{{yield to=‘inverse’}} works today | |
[1:59] | |
{{yield to=foo}} seemed the most natural to me | |
runspired [1:59 PM] | |
I’d love to reboot my named blocks proposal | |
[2:00] | |
I bikeshedded that with so many people but lost interest right when it started getting good :disappointed: | |
machty [2:01 PM] | |
@runspired i'd be happy to throw that around but only after this lands https://embercommunity.slack.com/archives/topic-forms/p1484419674000712 | |
machty | |
```{{#let-block sharedHeader as |person|}} {{person.name}} {{/let-block}} | |
{{complex-component | |
header=sharedHeader}} | |
{{complex-component``` | |
Show more… | |
Posted in #topic-formsToday at 1:47 PM | |
[2:01] | |
because that feature/functionality should exist regardless of a nicer syntax specific to single use named block slots | |
runspired [2:01 PM] | |
c | |
machty [2:02 PM] | |
so would everyone here :+1: an rfc for ^ | |
[2:03] | |
(does one already exist that specifically requests just this?) | |
mmun [2:03 PM] | |
no one has approached it this way | |
[2:04] | |
there is one or two dynamic block capture solutions which i disagree with strongly | |
[2:04] | |
and one static named block strategy by chris, i think? | |
cowboyd [2:20 PM] | |
I think that would make a great start, and is limited enough in scope that it stands a chance. | |
ryanto [2:31 PM] | |
late to convo, but we have an app that needs to pass blocks around and our solution is so hacky. capturing blocks would be nice (edited) | |
[2:32] | |
what were using https://github.com/ryanto/ember-content-for | |
machty [3:41 PM] | |
i can haz RFC https://github.com/emberjs/rfcs/pull/199 | |
mmun [3:45 PM] | |
nice | |
[3:46] | |
I’m looking through the RFCs. There’s an RFC there that I don't remember writing _at all_. | |
machty [3:46 PM] | |
hahaha | |
mmun [3:47 PM] | |
https://github.com/emberjs/rfcs/pull/43 | |
https://github.com/emberjs/rfcs/pull/72 | |
https://github.com/emberjs/rfcs/pull/193 | |
[3:47] | |
^ those are 3 the block ones | |
machty [3:49 PM] | |
interesting | |
[3:49] | |
https://github.com/emberjs/rfcs/pull/43#issuecomment-109802499 | |
[3:49] | |
nvm misread it | |
mmun [3:49 PM] | |
i’m pretty strongly against the rails style dynamic named yields (edited) | |
machty [3:51 PM] | |
can you link to what you mean | |
[3:51] | |
oh like cross-template? | |
ryanto [3:51 PM] | |
any reason why you dont like the rails capture/content_for? | |
mmun [3:52 PM] | |
there’s lots | |
[3:53] | |
the main one is that it just doesn’t work without weird hacks | |
locks [3:53 PM] | |
Same reason to discourage named outlets? | |
mmun [3:53 PM] | |
yes, but its worse than that | |
[3:53] | |
https://www.npmjs.com/package/ember-block-slots | |
npm | |
ember-block-slots | |
Support for targeted yield slots within a component block | |
ryanto [3:53 PM] | |
oh you mean in ember’s current state? yes totally strange hacks, but could this be fixed in a future state? | |
mmun [3:54 PM] | |
https://www.npmjs.com/package/ember-block-slots#usage (edited) | |
[3:54] | |
why do you need that first `{{yield}}`? | |
[3:54] | |
it is to execute side-effects | |
ryanto [3:55 PM] | |
its a hack, you need to capture the callers handlebars | |
mmun [3:55 PM] | |
rails strategy is fundamentally about side-effects | |
[3:55] | |
you leave a hole and fill it later | |
ryanto [3:55 PM] | |
yup | |
mmun [3:56 PM] | |
the static solution has no side-effects | |
ryanto [3:56 PM] | |
basically what i want is something like https://github.com/ef4/ember-elsewhere that doesnt need `send=(component)`, but can instead use block | |
[3:56] | |
i need to read about static solution | |
mmun [3:56 PM] | |
that solves a different problem | |
[3:57] | |
and is totally valid | |
ryanto [3:57 PM] | |
yes | |
mmun [3:57 PM] | |
e.g. to populate a sidebar | |
[3:57] | |
but if you don’t need side-effects you should avoid them | |
[3:57] | |
in the ember-elsewhere case, it’s hard to do it without side-effects | |
[3:58] | |
you’d need a declarative set of rules to determine what to render in the sidebar | |
[3:58] | |
and it would be pretty brutal | |
[3:59] | |
a good analogy is… in ruby there are both blocks and procs (edited) | |
[3:59] | |
both are useful | |
[4:00] | |
(technically there’s only procs, but :stuck_out_tongue: :stuck_out_tongue: ) (edited) | |
ryanto [4:00 PM] | |
similar to ruby, id like to be able to capture a block | |
cowboyd [4:00 PM] | |
there’s also lambdas, right? | |
mmun [4:00 PM] | |
yes, but they’re basically procs | |
cowboyd [4:01 PM] | |
except for return context | |
mmun [4:01 PM] | |
what i mean is that blocks, procs and lambdas are all represented as procs in the ruby vm code | |
cowboyd [4:01 PM] | |
gotcha. | |
mmun [4:01 PM] | |
but block are optimized to avoid allocating a proc unnecessarily | |
[4:03] | |
```def do_something_later | |
set_timeout 1000, do | |
puts "lol" | |
return | |
end | |
end | |
``` | |
[4:03] | |
^^ doesn’t make sense. you can’t hold onto a block and execute it later. blocks are for immediately invoked stuff | |
[4:03] | |
that’s the example i return to when thinking about procs vs blocks | |
machty [4:04 PM] | |
hmm | |
[4:04] | |
i mean, you could just `sleep` in `set_timeout`... | |
mmun [4:04 PM] | |
yeah that’d work | |
[4:04] | |
because you haven’t left `do_something_later` (edited) | |
cowboyd [4:05 PM] | |
Right, the return statement will raise a `LocalJmpError` | |
[4:05] | |
oh, I see, the `,` is deliberate. | |
machty [4:06 PM] | |
@hudabot describe TCP | |
mmun [4:06 PM] | |
```def do_something_later | |
set_timeout 1000, proc { | |
puts "lol" | |
return | |
} | |
end | |
``` | |
[4:06] | |
the return there is pretty pointless | |
[4:06] | |
:stuck_out_tongue: | |
cowboyd [4:06 PM] | |
it will raise a `LocalJmpError` I think. | |
mmun [4:07 PM] | |
hm, i would expect to to be the same as setTimeout(1000, function() { return }) | |
ryanto [4:07 PM] | |
ya localjumperror | |
[4:07] | |
iirc | |
mmun [4:07 PM] | |
anyways, sorry for my metaphysical divergence | |
cowboyd [4:07 PM] | |
```def do_something_later | |
set_timeout 1000, lambda { | |
puts "lol" | |
return | |
} | |
end | |
``` | |
will create a new call context. | |
mmun [4:08 PM] | |
the point is that i think both static blocks (machty’s rfc) and runtime hole-filling (ember-elsewhere) have their place (edited) | |
[4:08] | |
and just because you can sorta do the first with the latter doesn’t make it right :stuck_out_tongue: | |
cowboyd [4:09 PM] | |
So we have an RFC for `let-block` | |
[4:09] | |
is there one for `let`? | |
mmun [4:10 PM] | |
no, i keep slacking | |
[4:10] | |
:slack: | |
ryanto [4:10 PM] | |
agree re static, makes sense | |
mmun [4:15 PM] | |
btw, what i meant by “everything is a proc…” is that if you write | |
`def my_each(items, &block); puts block.class; end` it prints Proc | |
ryanto [4:16 PM] | |
yes because & is to_proc | |
mmun [4:16 PM] | |
not in the args list | |
ryanto [4:16 PM] | |
no? ah | |
mmun [4:16 PM] | |
well, i mean. it’s just syntax. you can think of it that way if you want | |
[4:17] | |
but the ruby vm will optimize the block (i.e. not allocate a proc/closure) if you don’t touch any of its Procy parts | |
ryanto [4:17 PM] | |
gotcha | |
cowboyd [4:17 PM] | |
Right, the moment you bind a block it becomes a proc. | |
mmun [4:18 PM] | |
these days you have to do more than just bind it | |
cowboyd [4:18 PM] | |
but if you never actually try to capture a reference to it, it doesn’t pay the overhead, is that what you’re saying? | |
mmun [4:18 PM] | |
`def my_each(items, &block); yield block; end` should be perf equivlanet to | |
`def my_each(items); yield; end` | |
[4:18] | |
(sorry if i butchered the syntax, i dont write much clever ruby code :P) | |
ryanto [4:19 PM] | |
block.call (?), but yes agree (edited) | |
samselikoff [4:19 PM] | |
Can someone explain let-block vs named yields, I've always thought named yields are friendly for beginners and solve a very real problem | |
[4:19] | |
Is it just that let-block accomplishes the same thing, and more? | |
mmun [4:19 PM] | |
what are named yields? (edited) | |
samselikoff [4:20 PM] | |
I haven't looked at RFC but slots or whatever? | |
ryanto [4:20 PM] | |
btw mmun, when i see let-block, block-slots, ember-elsewhere… i see them as the same problem “capture a block and use it some where in the future”, is my thinking right? | |
mmun [4:20 PM] | |
they seem like two sides of the same coin | |
samselikoff [4:20 PM] | |
Rails view layer | |
machty [4:20 PM] | |
@samselikoff you understand correctly | |
mmun [4:20 PM] | |
you bind a block to a name with let-block -> you yield to that name (edited) | |
samselikoff [4:20 PM] | |
I like rails view layer, I think it is a good easy to use abstraction that many rails deva understand use well? | |
[4:21] | |
I also agree with Ryan these seem like they share similar root problem | |
mmun [4:22 PM] | |
you can do that with ember-elsewhere | |
[4:22] | |
it doesn’t address how you e.g. customize power-select | |
samselikoff [4:22 PM] | |
But core ember | |
[4:22] | |
I need to see that | |
[4:22] | |
Why it dpesnt | |
machty [4:24 PM] | |
@samselikoff the RFC isn't too long and provides more context | |
cowboyd [7:54 PM] | |
One `let` rfc deserves another :slightly_smiling_face: https://github.com/emberjs/rfcs/pull/200 | |
mmun [7:58 PM] | |
:clap: | |
locks [8:01 PM] | |
@cowboyd I have to say I'm firmly against inline let | |
cowboyd [8:04 PM] | |
I assume there are reasons? | |
mmun [8:05 PM] | |
i’m firmly for it | |
[8:06] | |
we don’t have many tools to combat rightward drift in HTML | |
[8:06] | |
so I’d like to take advantage of the ones I can | |
locks [8:07 PM] | |
/shrug Don't indent with curly blocks (edited) | |
cowboyd [8:07 PM] | |
@locks I came around to it. I was in the block form camp at first, but after using it a lot, it adds clarity for the reasons @mmun says. | |
locks [8:07 PM] | |
I think it'll be easy too confusing | |
[8:07] | |
Lol editing slack actions | |
mmun [8:08 PM] | |
so there’s lots of pieces in play here, and I definitely want to hear your side of it @locks | |
locks [8:08 PM] | |
I'm getting home, I can try to words better | |
locks [8:29 PM] | |
how can I see markdown without it being rendered? | |
[8:29] | |
I don't know how to leave inline comments | |
cowboyd [8:30 PM] | |
can you do that in the changes section of the PR? | |
locks [8:31 PM] | |
@cowboyd another honest question, why not define your layouts in the component's definition? | |
[8:31] | |
toran does | |
[8:31] | |
hm | |
cowboyd [8:33 PM] | |
Because I want to have my handlebars and eat it too | |
[8:33] | |
(My turn to be on mobile) | |
[8:35] | |
That's certainly one approach, and it does improve the proximity problem somewhat. | |
locks [8:36 PM] | |
right, I was specifically talking about that | |
[8:36] | |
I don't think we have good ergonomics for that currently | |
[8:36] | |
I sort of like web component's approach | |
[8:37] | |
this has been generally discussed in the module unification rfc | |
cowboyd [8:37 PM] | |
But only somewhat. Because you've still got two separate parse trees. You can see where values are coming from but they aren't transparently available. | |
[8:37] | |
Like they are with JSX | |
locks [8:37 PM] | |
yes, it wouldn't be JSX | |
[8:38] | |
just single-file components, WC/polymer/vue style | |
[8:38] | |
(they're popular) | |
[8:39] | |
sorry for being all over the place, lots of things to consider at once and I'm still getting used to thinking that big xD | |
cowboyd [8:40 PM] | |
but we can have the power of JSX by increasing the power of our expression language | |
locks [8:41 PM] | |
I mean | |
[8:41] | |
with let, let-block, marten's import thing | |
[8:42] | |
I guess what I'm saying is I'd come at it from the JavaScript side myself | |
[8:42] | |
aka JSX | |
cowboyd [8:44 PM] | |
Why not just JSX then? | |
locks [8:45 PM] | |
indeed | |
cowboyd [8:45 PM] | |
I think there is an awesome opportunity here because JavaScript is just not that expressive | |
locks [8:46 PM] | |
you should be able to more easily do it with glimmer2 | |
[8:46] | |
so, I was thinking | |
[8:46] | |
clj doesn't have inline let | |
[8:46] | |
only block let | |
cowboyd [8:47 PM] | |
That's true although you could write A macro for it :smile_cat: | |
locks [8:47 PM] | |
yes! handlebars macros! | |
[8:47] | |
(plot twist, we already have them :troll: ) | |
cowboyd [8:48 PM] | |
Making them more accessible would be dope | |
[8:49] | |
Also JavaScript does have inline let :) | |
[8:49] | |
:stuck_out_tongue: | |
[8:50] | |
It las block let in the form of an IIFE | |
locks [8:51 PM] | |
> Many lanugages | |
[8:51] | |
JS isn't declarative | |
machty [8:52 PM] | |
i don't think inline let is non-declarative | |
[8:52] | |
an example of a violation would be actually altering the context halfway through | |
[8:53] | |
inline let is just a syntactically reasonably way to _establish_ the context | |
[8:55] | |
> with let, let-block, marten's import thing | |
[8:55] | |
not sure what marten's import thing is but `import` is another good example where the scope is established rather than mutated by a declaration/assignment | |
locks [8:56 PM] | |
I'm not quite following what you mean | |
machty [8:56 PM] | |
it sounds like you're :-1:ing certain features as non-declarative | |
[8:56] | |
(which is good) | |
[8:57] | |
i just don't think inline let is an example of such a thing | |
locks [8:57 PM] | |
I don't grok the "it establishes the context" | |
[8:57] | |
because I'm thinking there's no context switch | |
[8:57] | |
like olden each/with | |
[8:58] | |
can't find it, but @martndemus has a thing for explicitly importing components in template files | |
machty [8:59 PM] | |
i don't know what context switch you're referring to | |
locks [9:00 PM] | |
hm, let's go from the top, what does establishing a context mean? | |
cowboyd [9:00 PM] | |
> can't find it, but @martndemus has a thing for explicitly importing components in template files | |
I like this idea | |
locks [9:00 PM] | |
see. | |
[9:00] | |
:joy: | |
[9:01] | |
why, and do you know where it is because I can't rmemeber | |
[9:01] | |
I thought it was an RFC | |
machty [9:01 PM] | |
this has also been an idea proposed at core f2fs | |
cowboyd [9:01 PM] | |
It’s a good idea, though I’ve never seen it. | |
machty [9:02 PM] | |
@locks by establishing context i mean clearly establishing what all the known bindings are: block params + anything else that is known before glimmer will try and lock up a reference on the context | |
cowboyd [9:02 PM] | |
Also, worth noting that cljs _does_ do inline stuff that effects subsequent scope where it makes sense (just doesn’t do it with `let`) Like the `ns` macro. | |
locks [9:02 PM] | |
github search is useless | |
machty [9:02 PM] | |
and i think a minor adjustment to that story is block params + any `let` statements | |
locks [9:03 PM] | |
the `ns` macro is the most baffling aspect of clj | |
[9:03] | |
I could grok macros and whatnot, but I always had to go figure out namespaces | |
[9:03] | |
so we need to be careful | |
cowboyd [9:03 PM] | |
it serves the same function as `import` and `export` in javascript | |
[9:04] | |
do you object to the way it works or the fact that it effects the scope of the entire file, even though it appears to be limited to the top? | |
locks [9:04 PM] | |
mostly the syntax/semantics | |
cowboyd [9:05 PM] | |
but can you see why they might want to optimize for indentation | |
```(ns foo) | |
(def my-var 5) | |
``` | |
vs | |
```(ns foo | |
(def my-var 5)) | |
``` | |
locks [9:06 PM] | |
yes | |
[9:06] | |
but is `ns` restricted to the top-level of a module? | |
machty [9:07 PM] | |
to the REPLmobile | |
locks [9:07 PM] | |
hm, I'm seeing a problem with `{{import` | |
[9:09] | |
@machty `ns` in the actual repl works differently | |
machty [9:11 PM] | |
how's that | |
locks [9:11 PM] | |
I don't remember, it's been a while | |
[9:12] | |
https://www.beyondtechnicallycorrect.com/2013/04/14/loading-and-using-namespaces-in-the-clojure-repl/ likely related | |
[9:12] | |
hm doesn't totally explain it | |
machty [9:13 PM] | |
```borf=> (ns alex) | |
nil | |
alex=> (def a (ns lol)) | |
#'alex/a | |
lol=> | |
``` | |
[9:13] | |
i think `ns` is pretty side-effecty (edited) | |
[9:13] | |
only because it's grandspankenly obviously wrong to use it anywhere but the top of the file | |
[9:13] | |
cljs gives you a _few_ escape hatches, if you can even call them that, for setting global variables | |
[9:14] | |
ns could be considered one of them | |
locks [9:14 PM] | |
rust's module system is also super weird | |
[9:15] | |
clj was a bit of a disappointment. lovely language, utterly opaque ecosystem | |
machty [9:16 PM] | |
clj would benefit from ember experts | |
[9:16] | |
they are the masters of decomplection, n00bs at CoC | |
locks [9:16 PM] | |
CoC? | |
machty [9:16 PM] | |
convention over configuration | |
locks [9:16 PM] | |
I still remember the Pedestal framework being billed as next big thing | |
[9:16] | |
and then suddenly all the repos and websites disappear | |
[9:17] | |
"oh, we didn't like it, we use part of it internally now" | |
[9:17] | |
WhAt | |
cowboyd [9:17 PM] | |
`(ns wat)` expands to...... drum roll | |
[9:17] | |
```(do | |
(in-ns 'wat) | |
((fn* | |
loading__5569__auto__ | |
([] | |
(. clojure.lang.Var | |
(clojure.core/pushThreadBindings | |
{clojure.lang.Compiler/LOADER | |
(. (. loading__5569__auto__ getClass) getClassLoader)})) | |
(try | |
(refer 'clojure.core) | |
(finally | |
(. clojure.lang.Var (clojure.core/popThreadBindings))))))) | |
(if (. 'wat equals 'clojure.core) | |
nil | |
(do | |
(. clojure.lang.LockingTransaction | |
(clojure.core/runInTransaction | |
(fn* | |
([] | |
(commute | |
(deref #'clojure.core/*loaded-libs*) | |
conj | |
'wat))))) | |
nil))) | |
``` | |
locks [9:17 PM] | |
lovely macro (edited) | |
machty [9:18 PM] | |
lol | |
[9:18] | |
love it | |
[9:18] | |
i love clojure | |
[9:18] | |
i mean i haven't build anything in it | |
[9:19] | |
but when i get angry at ember i just `lein repl` and type `(+ 1 2 3 4 5)` just for funsies and i feel immediately better | |
locks [9:19 PM] | |
I tried to but, I ran into the ecosystem :X | |
[9:21] | |
last thing I did was a vehicle name generator for f-zero gx using core.logic | |
cowboyd [9:23 PM] | |
@machty I do the same thing, love to watch the macros incrementally expand. | |
[9:23] | |
expand, unexpand, expand all the way. | |
[9:24] | |
such relax | |
locks [9:24 PM] | |
incrementally expanding macros is my new prog rock ep | |
cowboyd [9:26 PM] | |
http://g.recordit.co/RNKY7oUZHB.gif (115KB) | |
mmun [9:26 PM] | |
`lein repl` sounds german | |
cowboyd [9:27 PM] | |
it’s `leine repl` when used in the singular. | |
locks [9:27 PM] | |
https://leiningen.org/img/leiningen.jpg (44KB) | |
cowboyd [9:30 PM] | |
the other thing that I just love about clojure is how hashes and arrays are also functions. | |
mmun [9:32 PM] | |
is decomplection a euphemism for "finding good primitives"? | |
locks [9:33 PM] | |
yes | |
cowboyd [9:33 PM] | |
if you haven’t watch simple vs easy it’s worth it | |
machty [10:02 PM] | |
uploaded this image: Image uploaded from iOS | |
Add Comment | |
machty [10:02 PM] | |
My friend looks like mr lein | |
----- Yesterday January 15th, 2017 ----- | |
locks [3:59 AM] | |
I'm not fooled, that's you with a mustache | |
machty [8:43 AM] | |
i am wondering if `let-block` should actually be `let-component` | |
[8:44] | |
contextual components are already a thing | |
[8:44] | |
you pass them into HoCs as attrs | |
[8:44] | |
and you render them with `(component)` | |
[8:45] | |
it seems weird that as an HoC that some of your attrs would be `yield`ed and others would be `component`ed | |
machty [8:50 AM] | |
```Prior RFC API: | |
{{#let-block fooBlock as |a b c|}} | |
Hello {{a}}, {{b}}, and {{c}}! | |
{{/let-block}} | |
Maybe it should be component centric: | |
{{#let-component fooComp bar=123 as |c|}} | |
{{c}} is a reference to the component. | |
{{c.bar}} = 123 (unless the HoC override | |
bar when calling component helper) | |
{{/let-component}} | |
Just as before, you pass it in as attrs... | |
{{x-foo header=fooComp body=fooComp footer=fooComp}} | |
{{x-foo header=fooComp body=fooComp footer=fooComp}} | |
{{x-foo header=fooComp body=fooComp footer=fooComp}} | |
//x-foo layout hbs | |
{{component header more=123 values=456}} | |
{{component body more=123 values=456}} | |
{{component footer more=123 values=456}} | |
``` | |
[8:52] | |
The yieldable block API isn't really congruent with contextual components | |
[8:56] | |
yieldable blocks only receive block params | |
[8:57] | |
hard to imagine how to merge a list of params with the hash of attrs that components receive when you render them | |
[8:59] | |
(and it would be bozo to try and write let-block / let-component positionalParams API) | |
machty [9:52 AM] | |
https://github.com/emberjs/rfcs/pull/199#issuecomment-272700009 | |
cowboyd [4:09 PM] | |
Is the fundamental tension here that you cannot pass named parameters to a block? | |
[4:10] | |
I.e. there is no such syntax as: | |
```{{#let-block hello as |a b c :more "less" :values "123"|}} | |
{{a}} {{b}} {{c}} | |
* More is {{more}} | |
* Values are {{values}} | |
{{/let-block}} | |
``` | |
machty [5:55 PM] | |
yes, something to that effect | |
[5:56] | |
blurg i thought i was going to avoid a slot syntax bikeshed but i don't think i can safely do so | |
locks [7:17 PM] | |
https://twitter.com/technomancy/status/819699427027755008 | |
technomancy @technomancy | |
LISPERS: Lisp is great coz you can create any abstraction you want! | |
ALSO LISPERS: Let's use functions named after registers of the IBM 704 | |
TwitterJan 12th at 7:15 PM | |
cowboyd [7:37 PM] | |
that’s a great quote. | |
machty [7:41 PM] | |
is that car cons stuff? | |
cowboyd [7:41 PM] | |
Yeah | |
locks [7:41 PM] | |
car and cdr I imagine | |
cowboyd [7:41 PM] | |
I knwo the `dr` is decrement register | |
[7:41] | |
and the `ar` is address register | |
[7:41] | |
but I can’t remember the `c` | |
locks [7:42 PM] | |
contents (via wiki) | |
cowboyd [7:43 PM] | |
@machty I didn’t see your response to my post about render syntaxt btw, just read the whole thing, so it kinda obviates my last comment | |
[7:43] | |
Sorry, if I came off as thick-headed. | |
machty [7:46 PM] | |
@cowboyd i never thought that | |
[7:46] | |
but here's more words! https://github.com/emberjs/rfcs/pull/199#issuecomment-272751317 | |
cowboyd [8:12 PM] | |
Yeah, it seems totally reasonable. What would you say about an rfc to normalize rendering? I actually see that as a huge potential win. | |
locks [8:12 PM] | |
normalize rendering? | |
cowboyd [8:14 PM] | |
i.e. for `{{foo}}` | |
property? render it! | |
function? call and render it! | |
helper? call and render it! | |
component? render it! | |
[8:14] | |
standing at the head of an expression means evaluation. | |
[8:14] | |
period. | |
locks [8:15 PM] | |
https://twitter.com/eaf4/status/818425177918803968 | |
Edward Faulkner @eaf4 | |
@fbeausoleil @locks This is the default behavior in all of Javascript. Functions and values are not the same thing. | |
TwitterJan 9th at 6:52 AM | |
cowboyd [8:16 PM] | |
Good thing this isn’t JavaScript :slightly_smiling_face: | |
locks [8:16 PM] | |
read the thread | |
cowboyd [8:18 PM] | |
Yeah, I disagree with it. | |
[8:18] | |
eval position is special | |
[8:18] | |
let’s say I have two functions | |
[8:20] | |
`fn1` `fn2` | |
I’d expect `(fn1 fn2)` to evaluate `fn1` and pass `fn2` by value to `fn1` (edited) | |
[8:20] | |
So I don’t think Trek’s example makes sense in this case: | |
I would _not_ expect | |
`{{my-child some-foo=aPropertyThatIsAFn}}` to evaluate `apPropertyThatIsAFn` | |
[8:21] | |
the thing being evaluated is `my-child` | |
[8:22] | |
but I _would_ expect | |
`{{aPropetyThatIsAFn}}` to evaluate the function | |
locks [8:22 PM] | |
handlebars isn't lisp, yet | |
cowboyd [8:23 PM] | |
I also would expect: | |
`{{my-child some-foo=(aPropertyThatIsAFn)}}` to evaluate it. | |
[8:23] | |
It isn’t but I think we make it closer by simplifying its rules | |
locks [8:23 PM] | |
there's no eval position | |
[8:23] | |
you're breaking handlebars | |
cowboyd [8:24 PM] | |
I’m questioning the constraints, yes | |
[8:24] | |
and I do think there is an eval position | |
[8:24] | |
François Beausoleil`s intuition was pointing to it | |
[8:28] | |
It’s just what you do when something is in eval position: | |
currently `{{aPropetyThatIsAFn}}` evals `Function.prototype.toString()` when a function is in eval position | |
[8:28] | |
and except for debugging, I can’t think when you would ever want that. | |
locks [8:29 PM] | |
it evals everything to toString | |
cowboyd [8:29 PM] | |
yes, but that is evaluation that is happening when a value appears in a certain position. | |
[8:29] | |
and not in others | |
[8:30] | |
so there _is_ something special about `{{this-value and not others}}` | |
[8:30] | |
it just doesn’t happen to be a very useful evaluation | |
locks [8:31 PM] | |
that is not my understanding of the system | |
cowboyd [8:32 PM] | |
of what it _is_, or what it should be? | |
[8:33] | |
Like, I am totally totally with you. This is _not_ the way it behaves today. | |
locks [8:34 PM] | |
https://embercommunity.slack.com/archives/topic-forms/p1484530202001073 I disagree with this | |
cowboyd | |
so there _is_ something special about `{{this-value and not others}}` | |
Posted in #topic-formsYesterday at 8:30 PM | |
[8:35] | |
but I don't look too much under the hood | |
[8:35] | |
I still maintain that this breaks handlebars | |
cowboyd [8:36 PM] | |
I don’t look under the hood much either. | |
locks [8:37 PM] | |
hm, I don't see how to do the change | |
cowboyd [8:38 PM] | |
But conceptually, which is simpler? | |
locks [8:38 PM] | |
I like lisp :P | |
cowboyd [8:38 PM] | |
I’m curious how this breaks handlebars though. | |
[8:38] | |
As in an API change? | |
[8:38] | |
or philosophically? | |
locks [8:38 PM] | |
API change | |
[8:39] | |
you're changing the semantics | |
[8:39] | |
it'll not only break existing apps, it'll break in possibly silent ways | |
cowboyd [8:39 PM] | |
theoretically (which has very little basis in practicality) the semantics should be a superset | |
[8:40] | |
right now | |
`{{aPropetyThatIsAFn arg1 arg2}}` | |
[8:40] | |
is an error | |
[8:40] | |
so really, I’m proposing _unbreaking_ handlebars | |
[8:41] | |
the only apps that would break would be apps that rely on this error behavior.... which would be odd to say the least. | |
[8:42] | |
I have no idea what this would mean for the implementation | |
cowboyd [8:50 PM] | |
but that’s why I was soliciting opinion, because for me having a single concept for `{{thingy .........}}` which is `evaluate thingy and render it` for some definition of evaluate is extraordinarily powerful and easy to intuit. | |
machty [8:50 PM] | |
derailment in t minus 30s | |
cowboyd [8:50 PM] | |
derailment should be the name of this channel. | |
machty [8:50 PM] | |
```{{#with-slots (component 'complex-component' a=123) as |slot|}} | |
{{slot 'header' as |attrs|}} | |
{{/slot}} | |
{{#slot 'footer' as |attrs|}} | |
{{/slot}} | |
{{slot 'body' (component 'wat' foo=123)}} | |
{{/with-slots}} | |
``` | |
cowboyd [8:51 PM] | |
did you just turn the problem inside out? | |
locks [8:51 PM] | |
irc rule #2: if a channel has a specific topic, 80% of the discussion will be off-topic | |
machty [8:51 PM] | |
yes, i decomplected!!!! | |
[8:52] | |
basically, i think i've convinced myself that whatever slot syntax we land on should be `(component)` centric | |
[8:52] | |
rather than template block centric (with positional block params) (edited) | |
[8:52] | |
so this is an attempt at a helper that collects slots, turns them into components, and passes them into the 'complex-component' as attrs | |
[8:53] | |
no new weird null zone funky syntax that the other RFCs have | |
[8:54] | |
i consider this a good idea regardless of whether some form of inline let / let-block is accepted | |
cowboyd [8:55 PM] | |
It’s really good | |
[8:56] | |
You can implement this today with `slot` as a contextual component, right? | |
machty [8:57 PM] | |
yeah, figure i'll try shortly | |
[8:57] | |
unless you wanna | |
cowboyd [8:57 PM] | |
like no change necessary. | |
[8:59] | |
nah, Imma go fill up my growlers. | |
ryanto [9:23 PM] | |
i like with slot, i can try to implement that | |
machty [9:25 PM] | |
i'm trying but i might likely fail | |
[9:25] | |
i'll let you know if i do | |
[9:25] | |
i don't actually know what's possible | |
ryanto [9:26 PM] | |
`{{#slot 'footer' as |attrs|}}`, what is attrs in this case? a=123? | |
machty [9:27 PM] | |
i think it is actually an instance of Component | |
[9:27] | |
with all the various properties merged into it already | |
[9:27] | |
like out `(component 'x-foo' bar=123)` might be rendered with `{{component xFooRef bar=456}}` | |
[9:28] | |
it's a bit wat but it's also pretty consistent / flexible with today's `(component)` usage | |
machty [9:44 PM] | |
@ryanto ok i don't have time to figure this out tonight (edited) | |
[9:44] | |
https://ember-twiddle.com/208b5d4a8c691f9ab882ec65514eb8c9?numColumns=2&openFiles=templates.components.complex-component.hbs%2Ctemplates.application.hbs | |
[9:45] | |
basically we need the ability to pass in something _like_ a contextual component | |
[9:45] | |
but it might be explicitly forbidden atm | |
mmun [10:48 PM] | |
https://embercommunity.slack.com/archives/topic-forms/p1484531547001105 | |
machty | |
basically, i think i've convinced myself that whatever slot syntax we land on should be `(component)` centric | |
Posted in #topic-formsYesterday at 8:52 PM | |
[10:48] | |
convince me plz (edited) | |
[10:50] | |
anonymous blocks are the right primitive imo. components have too much machinery. but maybe i missed which use case you’re talking about? I would like to understand the use cases being addressed. We should make a spread sheet of usecases vs. solutions. e.g. i think anonymous blocks is the right solution for power-select. (edited) | |
[10:53] | |
https://embercommunity.slack.com/archives/topic-forms/p1484529815001063 | |
locks | |
there's no eval position | |
Posted in #topic-formsYesterday at 8:23 PM | |
[10:55] | |
this comment is strange to me. clearly the first slot in an mustache/subexpression has different semantics than the remaining slots. | |
[10:57] | |
it seems fine to explore amending the semantics to support calling contextual things like `{{this.foo.bar blah blah}}`. i don’t think anyone is proposing to break ember. (edited) | |
[10:58] | |
there’s an issue with the ambiguity of `{{this.foo.bar}}` but it’s by no means a dealbreaker. e.g. you can disambiguate with `{{(this.foo.bar)}}` (edited) | |
cowboyd [11:11 PM] | |
what about just calling functions? | |
[11:11] | |
I think I see, basically `{{this.foo.bar}}` references a function | |
mmun [11:13 PM] | |
yeah, sure | |
[11:14] | |
i edited to “contextual things” there to keep it ambiguous :slightly_smiling_face: (edited) | |
cowboyd [11:14 PM] | |
ah, I thought I read it as helpers at first. | |
mmun [11:14 PM] | |
`{{this.foo.bar}}` have value-specific behaviour might be too trollish | |
[11:14] | |
e.g. execute if its a function, otherwise dont | |
[11:15] | |
it’s not obvious to me if that is too trollish atm | |
[11:15] | |
it gets worse when you have things like `onclick={{this.foo.bar}}` (edited) | |
cowboyd [11:15 PM] | |
does it? | |
[11:15] | |
oh, yeah | |
[11:15] | |
it does | |
mmun [11:16 PM] | |
`{{(this.foo.bar)}}` is an easy way to skip this issue :stuck_out_tongue: | |
cowboyd [11:16 PM] | |
I’m happy with `onclick={{action this.foo.bar}}` | |
mmun [11:16 PM] | |
that ship has sailed though | |
[11:16] | |
`onclick={{this.foo.bar}}` already works | |
[11:17] | |
but even if it hadn’t, I wouldn’t be a fan of value-specific semantics (e.g. determined by whether the value is callable or not) (edited) | |
[11:18] | |
^ it’s more subtle than how i stated… value-specific semantics are ok sometimes… ;/ | |
cowboyd [11:19 PM] | |
I think it could work, but it would be a fundamental breaking change. | |
mmun [11:19 PM] | |
i really dislike `{{action this.foo.bar}}` | |
[11:19] | |
and action in general | |
[11:20] | |
i feel like i’m the only one who feels this way | |
[11:20] | |
but I just want to use plain old functions | |
cowboyd [11:20 PM] | |
no, I’m also not the hugest fan | |
[11:20] | |
because it’s an escape hatch | |
[11:20] | |
it’s pressing the eject button on your context | |
mmun [11:20 PM] | |
e.g. if i have a custom button that take’s an onclick attribute and uses it as `<button onclick={{onClick}}>` | |
[11:21] | |
and is invoked by `{{my-button onClick=(|| console.log("maybe one day");)}}` | |
[11:22] | |
i’m jk about the lambda, | |
cowboyd [11:22 PM] | |
I think it’s fab | |
[11:22] | |
but I also think that action was an important step in the evolution. | |
mmun [11:23 PM] | |
there’s lots of good reasons for action to exist | |
cowboyd [11:23 PM] | |
I got no beef with action, but again, a lot of the time its a backstop | |
[11:24] | |
for the inability to declare abstractions natively | |
mmun [11:24 PM] | |
they solve a lot of design issues that you have when just using functons | |
cowboyd [11:24 PM] | |
but I think that `{{(eval-and-render-me-plz)}}` is :thumbsup::skin-tone-3: | |
mmun [11:24 PM] | |
e.g. what is `this` inside of a function call in the helper | |
[11:25] | |
`<button onclick={{this.handleClick}}>` might not behave the way you expect (edited) | |
[11:25] | |
so I appreciate actions for making everyone productive in the mean time | |
[11:27] | |
but I think react’s `<Button onClick={(e) => this.handleClick(e)}>` is better. and i’m not ashamed to try and get ember to that point. (edited) | |
cowboyd [11:31 PM] | |
`<button onclick={{(|e| (this.clickHandler e)}}>` | |
[11:31] | |
totally gratuitous | |
[11:32] | |
but I’m falling in love with this `λ` syntax | |
mmun [11:32 PM] | |
why not `<button onclick={{|e| (this.clickHandler e)}}>` | |
[11:32] | |
maybe that’s what you meant? parens didn’t match | |
cowboyd [11:33 PM] | |
I suppose it could be bare | |
[11:33] | |
oops | |
[11:33] | |
`<button onclick={{(|e| (this.clickHandler e))}}>` | |
[11:37] | |
I’m just used to lambda forms having surrounding `()` e.g. `(fn [x y])` from clj or `(lambda (x y))` from scheme, so I naturally gravitate towards `(|x| )` | |
[11:37] | |
How would it effect the parser? | |
mmun [11:38 PM] | |
it’s all fine from a parse pov | |
[11:38] | |
it’s invalid syntax atm | |
cowboyd [11:39 PM] | |
so true, but the more I see it the more I wantz. | |
[11:41] | |
but in terms of less crazy ideas, how hard would it be to actually implement the `{{(call-and-render)}}`? | |
[11:41] | |
would you need anything else for contextual helpers? | |
mmun [11:42 PM] | |
it already works | |
cowboyd [11:42 PM] | |
with any function? | |
mmun [11:42 PM] | |
ah, probably not | |
cowboyd [11:43 PM] | |
I was almost about to get up and dance :slightly_smiling_face: | |
mmun [11:43 PM] | |
people are against having things being able to be looked up on the context and globals | |
[11:44] | |
there was a suggestion that it needed to have some way to statically disambiguate | |
[11:44] | |
like {{(this.call-and-render)}} | |
cowboyd [11:47 PM] | |
I’m getting a parse error https://ember-twiddle.com/fb7c1624c537966498dab9b2436c3309?openFiles=templates.application.hbs%2C | |
[11:48] | |
I’m a proponent of prefixing context values with `this.` | |
mmun [11:48 PM] | |
me too | |
cowboyd [11:48 PM] | |
feel strongly that lexical values should have highest priority (over globals) (edited) | |
mmun [11:49 PM] | |
oh, everyone agrees | |
cowboyd [11:49 PM] | |
well that’s a relief. | |
mmun [11:49 PM] | |
it was a bug that that wasn’t always true | |
[11:49] | |
i think it was fixed | |
cowboyd [11:50 PM] | |
in fact, might be awesome to have a global sigil too, in the same vein as a `this.` for context | |
[11:50] | |
{{`/global-value`}} | |
mmun [11:50 PM] | |
https://github.com/wycats/handlebars.js/blob/master/src/handlebars.yy#L140-L148 | |
[11:50] | |
doesn’t include sexpr | |
[11:50] | |
oops | |
[11:50] | |
helperName is the first slot of a curly (edited) | |
cowboyd [11:53 PM] | |
But requireing `this.` to prefix values from the context is a super breaking change | |
[11:53] | |
I think it would be an exciting development, but highly break-o | |
locks [11:55 PM] | |
something something glimmer components | |
----- Today January 16th, 2017 ----- | |
machty [4:37 AM] | |
https://embercommunity.slack.com/archives/topic-forms/p1484538531001133 | |
mmun | |
convince me plz | |
Posted in #topic-formsYesterday at 10:48 PM | |
[4:37] | |
Some of this is coming from convos I've had with trek | |
[4:38] | |
Which elaborate on his ember camp talk that everyone references (edited) | |
[4:38] | |
We've been thinking about ways to extend/override components | |
[4:39] | |
Hmm you know i should just ask him what he thinks of with slots | |
[4:44] | |
But anyways the reason I like component centric is that it adds minimal bloat to the render api | |
[4:44] | |
Doing yield slots means expanding the yield api | |
[4:45] | |
The component approach has already proven its utility | |
[4:46] | |
Lots of apps pass in overridable bits in component form | |
[4:46] | |
With slots just lets you continue on that track without having to rewrite your higher order component's api | |
[4:47] | |
I think the higher order component case is key here | |
[4:47] | |
You want to be able to override internals with both a slot syntax and just passing an attr (is this controversial?) | |
[4:48] | |
But how would you write an HOC that allowed both? | |
[4:50] | |
In one case you render w {{component attrComp a=foo b=bar}} and the other you {{yield foo bar to=attrBlock}} | |
[4:52] | |
If the syntaxes were unified you'd need some way to pass simultaneously positional and named params | |
arielz [5:02 AM] | |
joined #topic-forms. Also, @taras joined. | |
fivetanley [9:50 AM] | |
dang, lotta decomplecting going on in this channel | |
locks [9:51 AM] | |
yeah, we gotta decomplect all the decomplecting | |
machty [10:07 AM] | |
@mmun curious for your response to all that | |
[10:07] | |
sounds like what i'm suggesting will be at odds with slots being "static" | |
mmun [10:09 AM] | |
I am not dogmatic about static vs. dynamic. There are just elements of the dynamic solution that are deeply unappealing to me in some cases. (edited) | |
[10:10] | |
like needing to {{yield}} to "register" side-effects | |
[10:12] | |
I can't help but make the analogy with procs & blocks again | |
machty [10:12 AM] | |
well before you do that, i don't think the with-slots solution suffers from that | |
mmun [10:12 AM] | |
{{yield foo bar to=attrBlock}} | |
{{yield foo bar to=&someComponent}} | |
machty [10:13 AM] | |
i mean, `with-slots` internally will yield, but that happens as an implementation detail to with-slots rather than something that all HOCs have to do | |
mmun [10:14 AM] | |
it's still deeply unsettingly to me. | |
[10:14] | |
but there's more | |
[10:14] | |
does `with-slots` invoke the component? (edited) | |
fivetanley [10:15 AM] | |
https://media.giphy.com/media/xkvd0OGbRt41G/giphy.gif (1MB) | |
[10:15] | |
there is reason to be upset, but this is my favorite gif | |
mmun [10:15 AM] | |
it's v good gif | |
[10:15] | |
@fivetanley are you still in TX? | |
fivetanley [10:15 AM] | |
c | |
mmun [10:16 AM] | |
https://embercommunity.slack.com/archives/topic-forms/p1484531459001101 | |
(just bubbling it back up) | |
machty | |
```{{#with-slots (component 'complex-component' a=123) as |slot|}} | |
{{slot 'header' as |attrs|}} | |
{{/slot}} | |
{{#slot 'footer' as |attrs|}}``` | |
Show more… | |
Posted in #topic-formsJan 15th at 8:50 PM | |
machty [10:17 AM] | |
`with-slots` yields the block passed to it to register side-effects (collecting all the slot blocks in a registry) and passing those slots in as attrs to the (component) you pass to it | |
mmun [10:17 AM] | |
`{{#with-slots (component 'complex-component' a=123) as |slot|}}{{/with-slots}}` | |
==? | |
`{{component 'complex-component' a=123}}` | |
machty [10:17 AM] | |
yes | |
mmun [10:18 AM] | |
ok so how do you curry a block/slot/whatever? (edited) | |
machty [10:19 AM] | |
so my idea, that is likely DOA (unless it can be made to work as an addon) | |
mmun [10:19 AM] | |
if its a good idea I don't like that it is fundamentally DoA :stuck_out_tongue: | |
machty [10:19 AM] | |
is that for each slot, we build an anonymous component that behaves as if it were created by `(component 'anonymous-component')` | |
mmun [10:19 AM] | |
we can hax glimmer | |
machty [10:20 AM] | |
and as a sneaky hack | |
[10:20] | |
the block param that each slot block takes is a reference to that anonymous component | |
mmun [10:20 AM] | |
what if you want to pass an array of blocks? | |
fivetanley [10:20 AM] | |
what advantage does this approach have over something like ember-block-slots? | |
mmun [10:21 AM] | |
we need to pin an answer to that question | |
machty [10:21 AM] | |
@fivetanley i'll answer in a moment | |
[10:21] | |
or maybe now? | |
[10:21] | |
@mmun what did you mean about array | |
mmun [10:21 AM] | |
sec, writing an example | |
[10:22] | |
```{{#my-table dataSource=recordArray}} | |
{{#column as |record|}} | |
{{record.id}} | |
{{/column}} | |
{{#column as |record|}} | |
{{record.name}} | |
{{/column}} | |
{{/my-table}} | |
``` | |
(edited) | |
machty [10:23 AM] | |
lemme know when i should have enough info/context to respond (edited) | |
mmun [10:24 AM] | |
that is a strawman that embodies the idea, but by no means do i think ^^ is the syntax that would end up being the solution | |
[10:25] | |
i would hope our solution to tables would be closer to what is possible in react, where you could pass an array of component factories (edited) | |
[10:25] | |
`<MyTable dataSource={recordArray} columns={ [Column1, Column2] }>` (edited) | |
mmun [10:26 AM] | |
hands the mic to machty | |
machty [10:27 AM] | |
ohhhh ok | |
[10:27] | |
so that goes beyond giving a named list of overrridable slots | |
[10:27] | |
(have any of the proposed slot RFCs addressed that use case?) | |
mmun [10:28 AM] | |
RFCs no (edited) | |
machty [10:29 AM] | |
maybe slots with the same name are passed in as arrays | |
mmun [10:29 AM] | |
sure | |
machty [10:30 AM] | |
and HOCs like table components can provide contextual components with the name built in so that end users don't have to type `slot 'column'` | |
mmun [10:31 AM] | |
```{{#my-table dataSource=recordArray}} | |
{{#column heading="ID" as |record|}} | |
{{record.id}} | |
{{/column}} | |
{{#column heading="Name" as |record|}} | |
{{record.name}} | |
{{/column}} | |
{{/my-table}} | |
``` | |
(edited) | |
[10:31] | |
if you keep down this path, this sort of thing ought to be possible as well ^ (edited) | |
machty [10:32 AM] | |
so i think that's all possible regardless of whether we opt for component or block centric | |
mmun [10:32 AM] | |
or maybe not | |
machty [10:32 AM] | |
i feel like i should clarify why i think component is a good idea (and what it actually means API wise) | |
[10:32] | |
unless that's already clear | |
mmun [10:33 AM] | |
the reason I'm knee-jerk softly oposed to components-centric is that I think something like {{#each}} being component centric would be strange | |
machty [10:34 AM] | |
let's figure out what that would actually look like | |
[10:36] | |
basically i'm not trying to somehow deprecate all of the yield API | |
mmun [10:36 AM] | |
I know | |
machty [10:36 AM] | |
for simple components that basically just wrap `each` and render items in a list, just use the yield API | |
[10:37] | |
but if you have a complex HOC and ONE of the things it happens to do is render multiple items in a list... then maybe container centric is OK? | |
[10:37] | |
so yeah, what's an example i/we can jot up | |
machty [10:43 AM] | |
Given x-foo layout: | |
```<div class="x-foo-header"> | |
{{component header headerText=headerTextFromXFoo}} | |
</div> | |
<div class="x-foo-footer"> | |
{{component footer footerText=footerTextFromXFoo}} | |
</div> | |
``` | |
Here are all the ways you can pass overridable bits into x-foo | |
```// application.hbs | |
// using only slots | |
{{#with-slots (component 'x-foo') as |s|}} | |
{{#s.slot 'header' as |c|}} | |
<h1>{{c.headerText}}</h1> | |
{{/s.slot}} | |
{{#s.slot 'footer' as |c|}} | |
<h1>{{c.footerText}}</h1> | |
{{/s.slot}} | |
{{/with-slots}} | |
// just passing in a (component) w today's API | |
{{x-foo header=(component 'x-foo-header-override')}} | |
// combo platter | |
{{#with-slots (component 'x-foo' | |
header=(component 'x-foo-header-override')) as |s|}} | |
{{#s.slot 'footer' as |c|}} | |
<h1>{{c.footerText}}</h1> | |
{{/s.slot}} | |
{{/with-slots}} | |
``` | |
(edited) | |
[10:43] | |
i forget if i've written up the latest, so here it is as i see it | |
[10:44] | |
@fivetanley (et al) the reason i favor this approach (the component-centric approach) is that it is compatible with how people are passing in / overriding components today | |
[10:45] | |
whereas slot syntax would build out the APIs specific to yielding | |
[10:45] | |
which use positional block params for passing data | |
[10:45] | |
which is at odds with the `attr=(component)` API and would always need this annoying translation layer (between positional block params and attr=) (edited) | |
[10:46] | |
not to mention we'd have to tell everyone who's already written HOCs via `attr=(component)` that the path forward is to rewrite their stuff using yield-centric slot syntax | |
fivetanley [10:48 AM] | |
interesting | |
[10:48] | |
i’m interested to see where this road leads | |
[10:51] | |
man JS devs have it so nice that people think about these things | |
[10:52] | |
you basically couldn’t do this in rails | |
[10:52] | |
without a bunch of weird presenter type things | |
machty [10:53 AM] | |
yeah | |
machty [11:28 AM] | |
@mmun is it possible to implement `with-slots` in an ember-twiddle? specifically i need a way to have the `slot` contextual component "stash" its yield block on the `with-slots` registry and 2) wrap those saved blocks in `(component)` anonymous components (edited) | |
[11:29] | |
i don't really know the glimmer limitations there | |
[11:29] | |
i'd really like to be able to play around with this pattern | |
cowboyd [12:04 PM] | |
When I read component-centric vs block-centric it makes me think of this: | |
In ruby, it was a constant source of pain in the `<= 1.8` days that the expressive power of methods and procs were different, and that you could not define one in terms of the other. | |
```proc do |capture *args &and_a_block| | |
# invalid syntax in prior to 1.9 | |
end | |
``` | |
That changed in 1.9 when procs could themselves capture both splat args and other procs and there was a palpable sigh of relief in the library author community because now there was no friction in generating new apis programmatically. Previously there was this false dichotomy which everyone felt, but few could place a finger on that made everything feel so much better when it went away. I know that’s a deep problem when applied to hbs, but is there consensus that it should be a long term goal? (edited) | |
machty [1:42 PM] | |
Here's a more fleshed out case for component-centric slots | |
[1:42] | |
https://gist.github.com/machty/c00c83f3fbefefa72cefb0bb2322fc4f | |
[1:46] | |
@cowboyd: I see the parallels | |
[1:47] | |
There's too many cases of multiple ways to do things in ember | |
[1:47] | |
It's like a depth first search | |
[1:48] | |
Follow your intuition, go down a path, find out 2 hours later you've hit a dead end and that in fact you need to use the OTHER API for accomplishing a similar thjng | |
[1:48] | |
Helpers vs components vs outlets | |
zigahertz [2:15 PM] | |
joined #topic-forms. Also, @cibernox joined. | |
cibernox [6:21 PM] | |
:hand::skin-tone-5: | |
davewasmer [6:28 PM] | |
joined #topic-forms | |
ryanto [6:28 PM] | |
Hey alex do you have that gist / markdown with all the form problems when we started this channel? | |
[6:28] | |
cant find it, wondering if it got eaten by slacks chat limit | |
machty [6:42 PM] | |
@ryanto https://gist.github.com/machty/68afad4c03109f36d4f4cffaae3c170b | |
[6:42] | |
updated it earlier today | |
ryanto [6:43 PM] | |
awesome ty! | |
locks [11:25 AM] | |
https://github.com/emberjs/rfcs/pull/200#issuecomment-273142254 :sob: | |
mmun [11:36 AM] | |
the intent is good | |
[11:37] | |
we should encourage him to submit a PR targeted at cowbody’s PR | |
[11:37] | |
that way we can discuss the differences | |
[11:38] | |
@cowboyd: what do you think of using a hash style for block-let? | |
[11:38] | |
i understand the reasoning, but it feels trollish to an outsider that block-let and inline-let have different apis (edited) | |
locks [11:39 AM] | |
I want to kill with, not add more things | |
lolmaus [11:42 AM] | |
joined #topic-forms by invitation from @mmun | |
mmun [11:45 AM] | |
The primary motivation for the `let` RFC is to decouple the if-like behaviour away from the local variable binding behaviour (edited) | |
[11:46] | |
This also gives us an opportunity to rethink the syntax, but that is secondary. (edited) | |
[11:47] | |
For that reason, I don’t see @lolmaus’s RFC as an alternative to the `let` RFC. (edited) | |
[11:48] | |
It is a power-up for `with`. (edited) | |
locks [11:49 AM] | |
but we can't remove the conditional behaviour | |
mmun [11:49 AM] | |
It is possible (and in my opinion, likely) that the `let` RFC will lead to a deprecation of `with`. In that event, it wouldn’t make sense to continue investing into `with`. (edited) | |
locks [11:49 AM] | |
if `let` gets in, that'll be my goal | |
mmun [11:51 AM] | |
Hi @lolmaus :slightly_smiling_face: | |
lolmaus [11:52 AM] | |
Hey @mmun, @locks. What do you think of the imperativeness of the inline form of `let`? | |
mmun [11:52 AM] | |
It is not imperative at all. | |
lolmaus [11:53 AM] | |
You open a large template, append a portion of code and use inline let. | |
mmun [11:53 AM] | |
it is a declaration of an alias (edited) | |
lolmaus [11:54 AM] | |
It either errors out because there's another inline let somewhere on this level, or you redefine a variable and some unrelated code breaks because it relies on the old value. | |
[11:55] | |
Depending on whether more than one inline let is forbidden | |
mmun [11:55 AM] | |
I implemented inline-let in `ember-let` | |
[11:55] | |
and I don’t understand your description | |
[11:55] | |
give me an example when you can (i assume you’re on your phone…) (edited) | |
lolmaus [11:56 AM] | |
Yes, I'm standing in a bus ATM :bus: , will try providing an example in a few hours. | |
mmun [11:56 AM] | |
:+1: | |
lolmaus [11:57 AM] | |
Does ember-let forbid more than one inline let on the same level? Or does it merge them? | |
mmun [11:57 AM] | |
It is not forbidden. I don’t think merge is the right word. They get nested | |
[11:58] | |
```{{let a = 1}} | |
{{let b = (multiplty a 2)}} | |
... | |
``` | |
(edited) | |
lolmaus [11:59 AM] | |
I'm AFK, thx for inviting me to the discussion. | |
mmun [11:59 AM] | |
is like | |
```{{#let a=1}} | |
{{#let b=(multiply a 2)}} | |
... | |
{{/let}} | |
{{/let}} | |
``` | |
(edited) | |
[11:59] | |
no problem. I want to make sure we consider all the best ideas. | |
cowboyd [12:12 PM] | |
https://embercommunity.slack.com/archives/topic-forms/p1484671080001375 | |
mmun | |
@cowboyd: what do you think of using a hash style for block-let? | |
Posted in #topic-formsToday at 11:38 AM | |
[12:13] | |
I don’t see a problem with this. It makes the block form a little more magical | |
[12:15] | |
but the inline form is more magical and seems to be really tripping people up. | |
[12:18] | |
Using cardinality to bind names to values is an anti-pattern. I.e. I wouldn’t like this code. | |
```{{#let 1 2 3 4 as |a b c d|}} | |
{{/let}} | |
``` | |
locks [12:20 PM] | |
inline-let gives me the sheevs | |
cowboyd [12:21 PM] | |
I think this reads just fine. | |
```{{#let a=1 b=2 c=3 d=4}} | |
{{sum a b c d}} | |
{{/let}} | |
``` | |
Based on my knowledge of the runtime at the time I was implementing `let` I didn’t see how this was possible. | |
[12:21] | |
without making deeper changes than just adding a helper | |
locks [12:21 PM] | |
```{{#let (hash one=1 two=1) as |blurp|}} | |
{{blurp.one}} | |
{{/let}} | |
``` | |
^ what people do with contextual components | |
[12:21] | |
which I think is fine | |
[12:21] | |
given that it's already a pattern | |
[12:22] | |
I've seen it used with `with` too | |
cowboyd [12:22 PM] | |
Once you start to really lean on it, it really suffers from “aww do I have to?” syndrome. | |
mmun [12:24 PM] | |
using `hash` makes optimizations harder (edited) | |
[12:25] | |
not a strong argument for the user, but a strong one for implementers :stuck_out_tongue: | |
cowboyd [12:28 PM] | |
user argument: if you’ve never seen ember before compare `{{#let name=value}}` vs `{{#let (hash name=value)}} as |thing|}}` (edited) | |
mmun [12:28 PM] | |
yep | |
[12:29] | |
the word hash is very specific | |
cowboyd [12:29 PM] | |
if a hash is really what you want: `{{#let thing=(hash name=value)}}` | |
mmun [12:29 PM] | |
it’s just a map. or can you prove that it uses hashes? (edited) | |
cowboyd [12:30 PM] | |
yeah, I actually don’t like the `hash` helper | |
[12:30] | |
name | |
mmun [12:30 PM] | |
that ship has sailed :stuck_out_tongue: | |
[12:30] | |
i might have implemented it.. | |
locks [12:31 PM] | |
don't named arguments make let megamorphic | |
cowboyd [12:32 PM] | |
That sounds pretty awesome! | |
[12:32] | |
(but only because I don’t know what it means) | |
mmun [12:32 PM] | |
i think there are two many layers of abstraction between the JIT and handlebars to be able to answer that | |
[12:32] | |
megamorphic a JIT heuristic | |
[12:33] | |
it means “very polymorphic" | |
[12:33] | |
and thus, tends to not get optimized for any specific type | |
locks [12:33 PM] | |
@cowboyd me neither, but didn't I sound really cool | |
mmun [12:33 PM] | |
this isn’t a bad thing, though. if the function is genuinely megamorphic you don’t want to specialize for every possible type (edited) | |
locks [12:33 PM] | |
but I do mean, won't it bust the shape up | |
[12:34] | |
and deopt | |
cowboyd [12:34 PM] | |
@locks I was thinking of like megalodon swooping in and swallowing the entire scope. | |
machty [12:44 PM] | |
There should be a hash literal syntax | |
[12:44] | |
(Wat=lol) | |
cowboyd [12:47 PM] | |
I like that a lot. See also `(wat: lol)`, `(:wat lol)` | |
[12:47] | |
although I think NV pairs are so established elsewhere in hbs, that `=` is the only real alternative | |
locks [12:50 PM] | |
something something clojurescript | |
machty [1:11 PM] | |
It'd have to be = | |
cowboyd [2:06 PM] | |
That actually might be a compelling alternative `{{#with (firstName="bob" lastName="Dobalina") as |person|}}` I’ll include it in the alternatives section. | |
locks [2:07 PM] | |
I thought `()` would mean an invocation, with the first item being special | |
cowboyd [2:08 PM] | |
You have a point, this would definitiely have to be a special case. | |
locks [2:09 PM] | |
ambiguity :\ | |
cowboyd [2:10 PM] | |
`(# firstName="bob" lastName="dobalina")` | |
mmun [2:22 PM] | |
there's no ambiguity with `(firstName="bob" lastName="Dobalina")` | |
[2:22] | |
it just requires one token look ahead | |
locks [2:26 PM] | |
for programmers | |
[2:26] | |
it's confusing enough to have to use parens for nested expressions | |
samselikoff [2:27 PM] | |
`{{#with (firstName="bob" lastName="Dobalina") as |person|}}` is kinda awesome | |
locks [2:28 PM] | |
would that be falsey if both named args were falsey? | |
mmun [2:28 PM] | |
wat | |
locks [2:29 PM] | |
with has conditional semantics | |
[2:29] | |
I'm asking how that interplays | |
mmun [2:29 PM] | |
they don't depend on the fields of the value | |
locks [2:29 PM] | |
what do you mean | |
mmun [2:30 PM] | |
{{#with (firstName="") as |person|}} | |
{{#with (hash firstName="") as |person|}} | |
{{#with this.personWithEmptyName as |person|}} | |
[2:30] | |
`with` behaves the same way for all of them | |
[2:30] | |
which is to display the block (edited) | |
locks [2:39 PM] | |
it doesn't | |
[2:40] | |
the last one doesn't display a block | |
[2:40] | |
if the first item is falsey, it doesn't render | |
[2:42] | |
`hash` returns an object, so that's never falsey | |
[2:42] | |
so I'm wondering about the named args stuff | |
mmun [2:50 PM] | |
regardless, they would all have the same semantics | |
locks [2:51 PM] | |
I don't like breaking with for everyone | |
mmun [2:51 PM] | |
what on earth are you talking about | |
locks [2:52 PM] | |
https://embercommunity.slack.com/archives/topic-forms/p1484681404001479 | |
mmun | |
{{#with (firstName="") as |person|}} | |
{{#with (hash firstName="") as |person|}} | |
{{#with this.personWithEmptyName as |person|}} | |
Posted in #topic-formsToday at 2:30 PM | |
[2:52] | |
you're saying the three forms behave the same, and they render the block | |
mmun [2:52 PM] | |
i don't care what they do... (edited) | |
[2:52] | |
as long as they do the same thing! (edited) | |
locks [2:52 PM] | |
but the last one doesn't | |
[2:52] | |
currently | |
[2:52] | |
the last one renders the else block | |
[2:53] | |
so you need to change the existing semantics | |
mmun [2:53 PM] | |
that's not true | |
locks [2:53 PM] | |
I just tried it | |
mmun [2:53 PM] | |
you did it wrong (edited) | |
[2:53] | |
but it's besides the point | |
[2:53] | |
the should have the same semantics | |
[2:53] | |
whatever the current semantics are | |
[2:53] | |
they should, all 3, do the same thing. | |
locks [2:56 PM] | |
welp | |
mmun [2:59 PM] | |
https://ember-twiddle.com/8625148b9e90ece2308cac6147b08b10?numColumns=2&openFiles=templates.application.hbs%2Ccontrollers.application.js | |
cowboyd [3:00 PM] | |
`this.person` works like today? | |
mmun [3:01 PM] | |
can you elaborate? | |
cowboyd [3:01 PM] | |
Like in your twiddle, you used `this.person` I wasn’t aware that was a thing. | |
mmun [3:02 PM] | |
oh yes. since the very beginning | |
[3:02] | |
it can be used to break ties vs. globals and locals | |
cowboyd [3:02 PM] | |
well that’s an embarassing gap in my knowledge | |
lolmaus [3:03 PM] | |
@mmun Trying `ember-let` in a Twiddle, and it says "let is not a helper". :thinking_face: | |
mmun [3:05 PM] | |
:poop: | |
[3:07] | |
how does the ember-twiddle even support addons | |
[3:07] | |
:glimmer: | |
[3:10] | |
I don't know why it doesn't work in ember-twiddle | |
lolmaus [3:16 PM] | |
@mmun Have you tried it yourself? | |
mmun [3:16 PM] | |
yes | |
lolmaus [3:16 PM] | |
@mmun Does it work for you? | |
mmun [3:16 PM] | |
no | |
lolmaus [3:16 PM] | |
Ok... I'll try to describe with words then. | |
[3:19] | |
@mmun Imagine you've got a template where you use `ember-let` like this: | |
```{{let apples=(array 1 2 3)}} | |
<p> | |
We've got {{array-reduce apples}} apples. | |
</p> | |
``` | |
This is followed by lots of Handlebars and HTML code. | |
You open this file and you don't remember there's `apples` defined somewhere above. You decide to define it: | |
```{{let apples="Malus pumila"}} | |
``` | |
[3:20] | |
And suddenly your app crashes because `"Malus pumila".reduce` is not a function. | |
[3:21] | |
@mmun | |
mmun [3:22 PM] | |
how is that any different from a block form? | |
[3:24] | |
if you want to keep the scope of your variables tight, then use the block form | |
[3:24] | |
in practice this doesn't really happen | |
[3:26] | |
```{{let apples=(array 1 2 3)}} | |
<p> | |
We've got {{array-reduce apples}} apples. | |
</p> | |
<div> | |
{{let apples="Malus pumila"}} | |
An {{apples}} a day keeps the doctor away. | |
</div> | |
<p> | |
We've still got {{array-reduce apples}} apples. | |
</p> | |
``` | |
[3:26] | |
Under the current scoping rules, this will work correctly. | |
[3:27] | |
the second `let` definition only lives until the end of the `div` | |
lolmaus [3:27 PM] | |
@mmun What if you use two lets on one level? | |
mmun [3:27 PM] | |
that case will break | |
[3:27] | |
```{{let apples=(array 1 2 3)}} | |
<p> | |
We've got {{array-reduce apples}} apples. | |
</p> | |
{{let apples="Malus pumila"}} | |
<p> | |
An {{apples}} a day keeps the doctor away. | |
</p> | |
<p> | |
We've still got {{array-reduce apples}} apples. | |
</p>``` | |
(edited) | |
[3:28] | |
^ bad times | |
lolmaus [3:28 PM] | |
@mmun If the developer used a block for manually, without the magical transformation, they'd be seeing exactly what they're doing. | |
But this inline let is doing something un-obvious. That's perefectly fine for an addon, but for Ember core it's too funky, IMO. | |
mmun [3:29 PM] | |
I disagree. It works fine in every other programming language with a declarative let. | |
lolmaus [3:30 PM] | |
In other languages an assignment does not influence code above it. But with inline `let`, it does! :scream_cat: | |
mmun [3:32 PM] | |
ok, I respect your point and would be ok with forcing inline-let's to be at the top of a block (edited) | |
[3:32] | |
or at least to not have multiple on the same level (edited) | |
[3:33] | |
or some kind of rule to alleviate what you're saiyng. | |
[3:33] | |
```let apples = vec![1,2,3]; | |
println!("We've got {} apples.", apples.iter().sum()); | |
let apples = "Malus pumila"; | |
println!("An {} a day keeps the doctor away.", apples); | |
println!("We've still got {} apples.", apples.iter().sum()); | |
``` | |
[3:33] | |
In rust, this would throw a compiler error. | |
locks [3:33 PM] | |
@mmun I see where we talked last each other | |
mmun [3:34 PM] | |
@lolmaus my understanding of your argument is that we can't throw a compile-time error the way Rust does here, so we have resolve this issue some other way. (edited) | |
locks [3:34 PM] | |
Let me try to reformulate, with with named arguments is always truthy? Could you mix positional and named args? What would that mean? | |
mmun [3:35 PM] | |
for what it's worth, this _would_ compile: | |
```let apples = vec![1,2,3]; | |
println!("We've got {} apples.", apples.iter().sum()); | |
{ | |
let apples = "Malus pumila"; | |
println!("An {} a day keeps the doctor away.", apples); | |
} | |
println!("We've still got {} apples.", apples.iter().sum()); | |
``` | |
[3:37] | |
@locks: I see. I was just entertaining the idea. I'm not in favour of giving `with` the additional semantics laid out in Andrey's RFC 1) because we missed the boat on the original design and it would be too confusing to have support both positional _and_ named arguments and 2) we have an opportunity with `let` to get it right without the baggage. (edited) | |
locks [3:39 PM] | |
As it's probably obvious by now, I agree with :skull: with, was going down that road though | |
[3:39] | |
Seems like it introduces complexity | |
mmun [3:40 PM] | |
Complexity is ok. Ember-concurrency is complex. | |
locks [3:40 PM] | |
We can do regular named params with let right | |
mmun [3:40 PM] | |
but yeah, unnecessary complexity is not ok. | |
locks [3:41 PM] | |
E-c is trying to solve concurrency, not bind some lexical values ;x | |
lolmaus [3:42 PM] | |
What if we prevent inline `let` from affecting the code above it? (edited) | |
[3:42] | |
sorry | |
mmun [3:42 PM] | |
that's already the case | |
locks [3:43 PM] | |
Please define above | |
mmun [3:43 PM] | |
```{{let color="red"}} | |
{{color}} | |
{{let color="blue"}} | |
{{color}} | |
``` | |
=> red blue | |
[3:44] | |
the binding only applies from them declaration until the end of the block | |
lolmaus [3:44 PM] | |
@mmun Oh then my objection wasn't valid. I'm sorry. | |
mmun [3:44 PM] | |
It is valid. | |
[3:44] | |
I object to your counter-objection. | |
lolmaus [3:44 PM] | |
:scream: | |
mmun [3:45 PM] | |
If you have a large template like: | |
```{{let color="red"}} | |
I love {{color}}! | |
... lots of stuff ... | |
I still love {{color}}! | |
``` | |
```I love red! | |
... lots of stuff ... | |
I still love red! | |
``` | |
(edited) | |
[3:46] | |
and someone comes along and introduces new code _that is also at the same level_ you can have issues | |
locks [3:46 PM] | |
Can we error? | |
[3:46] | |
Duplicate definition | |
mmun [3:47 PM] | |
```{{let color="red"}} | |
I love {{color}}! | |
... lots of stuff ... | |
{{let color="blue"}} | |
Mary's favourite color is {{color}}! | |
... lots of stuff ... | |
I still love {{color}}! | |
``` | |
```I love red! | |
... lots of stuff ... | |
Mary's favourite color is blue! | |
... lots of stuff ... | |
I still love blue! <-- oops | |
``` | |
(edited) | |
[3:48] | |
Errorring for a duplicate definition for the same name AND the same level is a pretty reasonable compromise. (edited) | |
locks [3:48 PM] | |
Rust style ;) | |
mmun [3:48 PM] | |
no - rust is perfectly content with the "oops" scenario | |
[3:49] | |
but that is because you don't normally edit the middle of functions in code (edited) | |
[3:49] | |
but with templates you do (and very often!) (edited) | |
locks [3:49 PM] | |
Js style? :[ | |
mmun [3:50 PM] | |
I am pretty happy with that compromise. | |
lolmaus [3:50 PM] | |
My point is that with the block form there's no way this could happen unnoticed. Because the user consciously defines the start and the end of a variable's scope. | |
But this inline thing is shady. It's like we're creating a hole in the floor, realize it's to dangerous so we cover it with wood planks. Now people are gonna stumble on the planks, but at least they don't fall into the hole. | |
mmun [3:51 PM] | |
I'm going to need a non-carpentry metaphor | |
[3:52] | |
concrete issues that can occur | |
lolmaus [3:53 PM] | |
@mmun The block form is perfectly safe. The inline form creates a problem. We're gonna work around the problem by forbidding more than one invocation on the same level. People are gonna run in this limitation and they'll be frustrated. | |
locks [3:53 PM] | |
I don't actually agree with the block argument | |
[3:53] | |
The delimiters are at the beginning and the end | |
mmun [3:53 PM] | |
What does safe mean? | |
[3:53] | |
It's not concrete. | |
locks [3:53 PM] | |
With sufficient coffee you don't know the scope you're in | |
mmun [3:54 PM] | |
my concern with block-let is that it causes your templates to drift to the right. | |
lolmaus [3:54 PM] | |
Safe = nothing un-obvious happens under the hood. | |
mmun [3:54 PM] | |
inline let is not surprising to me. | |
lolmaus [3:55 PM] | |
Because you're the author of the addon? :trollface: | |
mmun [3:55 PM] | |
because I've programmed in functional languages. | |
[3:56] | |
`let` is the poster child for declarative bindings | |
lolmaus [3:56 PM] | |
@mmun I consider extra indentation to be a price you have to pay for doing logic in templates. :smiling_imp: | |
I think I understand why inline let scares me. It makes Handlebars feel like JS. Where instead of defining HTML structures you write commands line by line. | |
mmun [3:57 PM] | |
to me the block form and the inline form are exactly equivalent | |
[3:57] | |
one just doesn't force an indent, but at the cost of lasting until the end of the scope | |
cowboyd [3:57 PM] | |
@lolmaus I originally wrote the addon with block form only. | |
mmun [3:57 PM] | |
if you want more scope-control then i would use the block form | |
cowboyd [3:57 PM] | |
and it was ok, and I was only lukewarm on the inline form | |
locks [3:57 PM] | |
Most langs with let don't allow multiple declarations | |
cowboyd [3:57 PM] | |
but once you accept it into your lexicon, it really disappears into the background in a way that the block form doesn't | |
mmun [3:58 PM] | |
that's not true. | |
[3:58] | |
most languages with `let` allow you to shadow previous bindings | |
[3:58] | |
JS is the exception | |
locks [3:58 PM] | |
:thinking_face: | |
[3:58] | |
What am I confusing it with then | |
mmun [3:58 PM] | |
```let a = 1; | |
let a = a*a; | |
``` | |
[3:59] | |
i do this all the time in rust haha | |
locks [3:59 PM] | |
You are a bad person | |
mmun [3:59 PM] | |
no | |
locks [4:00 PM] | |
Good thing ember is a js fw then | |
mmun [4:00 PM] | |
I wouldn't use it in the example above | |
[4:00] | |
but in rust it's very useful | |
locks [4:01 PM] | |
Rust warns me about unused var :joy: | |
mmun [4:01 PM] | |
e.g. you can downcast a mutable reference to a immutable reference temporarily | |
[4:01] | |
for better type safety | |
locks [4:02 PM] | |
Ok, you can't rebind a non mut let, nvm | |
[4:02] | |
Two "let count = 0" is an error :thinking_face: | |
mmun [4:03 PM] | |
```fn main() { | |
let mut foo = vec![1,2,3]; | |
let foo = &mut foo; // downcast ownership -> mutable reference | |
let foo: &Vec<_> = foo; // downcast mutable reference -> immutable reference | |
foo.sort(); // errors! | |
} | |
``` | |
(edited) | |
cowboyd [4:09 PM] | |
imho, if someone sees `let` in handlebars and thinks “hmmm, what is this imperative construct doing here?” then there has already been a failure on the part of the community to communicate the essence of what handlebars is about. The first time I saw `let` in Haskell, i did not think “hmmm.... what is this imperative construct doing in haskell?” I thought instead “hmmm, how do I re-interpret my understanding of this construct to fit inside of a system free of side effects?" because for all its problem with messaging, they are crystal clear on this point: evaluation is _not_ imperative” The strength of the paradigm eliminated that interpretation. | |
[4:10] | |
I feel crystal clear about this in hbs | |
mmun [4:11 PM] | |
strong confirm | |
cowboyd [4:12 PM] | |
Unfortunately, it’s a very tricky thing to drive home this message and not come off like a cretin :slightly_smiling_face: (edited) | |
slackbot Custom Response [4:12 PM] | |
:explicitwarning: We'd love for this to remain an awesome place for all Emberers. Helps us out by editing that message. :point_up: https://github.com/cromwellryan/embercommunity-slack-guidelines/blob/master/CodeOfConduct.md | |
new messages | |
mmun [4:13 PM] | |
That paragraph felt good. | |
lolmaus [4:34 PM] | |
@cowboyd I was incorrect in understanding how inline let compiles. I believe, your RFC would really benefit from an example of how two inline lets on the same level are transformed. | |
cowboyd [4:35 PM] | |
I agree, but there’s the way it works currently in the addon, but there’s also the way it _ought_ to work of which I’m not as sure. | |
[4:36] | |
seems like the options are warn, error, or shadow. | |
locks [4:48 PM] | |
My vote is error since the others are silent | |
[4:48] | |
Error also potentially provides the most guidance | |
machty [5:48 PM] | |
how bout error when building for prod | |
[5:49] | |
actually, not sure which error you're referring to | |
[5:49] | |
but there was an example that came up the other day that would have been annoying if it'd error in dev | |
locks [6:15 PM] | |
@machty `{{let a=3}}{{let a=3}}` should error with binding already exists (or somesuch) | |
[6:15] | |
> SyntaxError: Identifier 'a' has already been declared | |
[6:15] | |
(node) | |
[6:16] | |
IMO shadowing (same scope) is confusing in templates | |
[6:16] | |
and a deprecation is still a silent error | |
[6:17] | |
unless you turn deprecation warnings into errors for production builds, but that's also annoying because it tells you about the problem at the 11th hour | |
machty [6:21 PM] | |
Yeah that seems reasomabe | |
[6:21] | |
Oh I remember what it was: someone proposed erroring when you don't end up using a let car | |
[6:21] | |
Var | |
locks [6:41 PM] | |
that seems more like a linting warning | |
cowboyd [10:54 PM] | |
While we’re on the subject of language semantics, just watched this short talk which has some pretty cool moments. Definitely has me wanting to try out Racket https://www.youtube.com/watch?v=TfehOLha-18 | |
YouTube Racket Lang | |
(sixth RacketCon): Alexis King -- Languages in an Afternoon | |
(edited) | |
----- Today January 18th, 2017 ----- | |
machty [9:10 AM] | |
that guy seems pretty legit | |
[9:10] | |
daring to futz w mirror displays mid prezo | |
[9:10] | |
also racket seems awesome | |
[9:11] | |
how does the racket platform compare to LLVM? | |
mmun [9:48 AM] | |
or ajax, for that matter? | |
machty [9:56 AM] | |
so what's up peoples | |
mmun [9:56 AM] | |
my (first) plane got delayed an hour (edited) | |
[9:57] | |
which makes me less mad about having a 1.5 hour layover | |
locks [9:57 AM] | |
data is up son | |
machty [9:57 AM] | |
thought that was actions | |
mmun [9:58 AM] | |
data up. new thing we’re trying | |
locks [9:58 AM] | |
actions are data | |
[9:58] | |
it's the new lisp era | |
[9:58] | |
`let` it wash over you and elevate you to new heights | |
machty [9:59 AM] | |
let it drift me rightward | |
locks [10:01 AM] | |
https://twitter.com/jessilikestech/status/821501700968058880 this is what monads get you | |
Jessi Aboukasm @JessiLikesTech | |
Hey @Twitter you might want to unwrap your Optionals before displaying them on the watch app :grimacing::see_no_evil: https://pbs.twimg.com/media/C2aPcPnUkAAkDzt.jpg | |
TwitterYesterday at 6:37 PM (14KB) | |
mmun [10:02 AM] | |
I prefer that | |
machty [10:02 AM] | |
i have a weird spider sense where convincing the powers that be to allow/add more powerful enhancements to Hbs syntax would be more successful if i made more racket comparisons than clojure comparisons | |
[10:03] | |
if there's anything i've learned since getting involved in Ember it's how to package imperfect/not-totally-fleshed-out-ideas for improvement in the language of some open source underdog | |
mmun [10:03 AM] | |
yeah. racket & Dijkstra/von Neumann quotes are more thought-leadery than clojure/rich hickey | |
[10:04] | |
referencing smalltalk is good too (edited) | |
machty [10:04 AM] | |
uploaded this image: Pasted image at 2017-01-18, 10:04 AM | |
Add Comment | |
machty [10:04 AM] | |
are these images supposed to mean anything | |
cowboyd [10:05 AM] | |
@locks @machty actions are data as they travel downwards | |
mmun [10:05 AM] | |
the “stable" one reminds me of graphs i learned in chaos theory | |
locks [10:06 AM] | |
I don't like batteries included | |
[10:06] | |
I have to wait for them to recharge instead of just swapping out | |
mmun [10:06 AM] | |
locks i dont think we can be friends | |
locks [10:06 AM] | |
:-1: | |
[10:06] | |
IDE? heavy. bigly. | |
[10:06] | |
mature? what is this, senior home, we need the blood of teenagers (literally) | |
[10:07] | |
the best of? compromise, weak | |
mmun [10:07 AM] | |
http://mathworld.wolfram.com/images/eps-gif/LogisticEquationBifurcation_850.gif (11KB) | |
locks [10:07 AM] | |
that looks like someone trying to puncture a zit | |
[10:07] | |
aka, amazing | |
mmun [10:08 AM] | |
it is amazing… but not for that reason | |
[10:09] | |
@machty ok here’s the thing | |
[10:09] | |
if compiled templates have the ability to bind arbitrary blocks (they might even already have this feature…) (edited) | |
[10:09] | |
you can actually just write your own lang on the glimmer vm | |
[10:09] | |
if only someone had designed a hbs alternative... | |
cowboyd [10:10 AM] | |
> if compiled templates have the ability to bind arbitrary blocks (they might even already have this feature…) | |
not fully following. | |
mmun [10:11 AM] | |
in glimmer, today, we have all the machinery to support yielding to arbitrary blocks | |
cowboyd [10:11 AM] | |
what is the interface for a “block” at the low level? | |
mmun [10:11 AM] | |
{{yield to=”inverse”}} turns into [‘yield’, someIntegerRepresentingTheBlock] | |
cowboyd [10:12 AM] | |
something that just returns some DOM? | |
mmun [10:12 AM] | |
it’s an array of “opcodes" | |
[10:13] | |
let me phrase it different | |
[10:13] | |
I suspect that you can craft a compiled template that has bound blocks | |
[10:13] | |
in the way that #let-block can bind blocks | |
[10:14] | |
that compiled template will not be something that the handlebars -> compiled template compiler can do | |
[10:14] | |
but it may be useful for experimenting | |
[10:15] | |
e.g. write some handlebars -> get a template -> monkeypatch the template before loading the app | |
cowboyd [10:18 AM] | |
monkey patch as in monkeypatch the opcodes? | |
mmun [10:19 AM] | |
yeah | |
[10:19] | |
the compiled template is just json | |
[10:19] | |
you can tweak it | |
[10:21] | |
(technically speaking, it’s not opcodes yet) | |
machty [10:21 AM] | |
oh i was thinking: there might be a way to experiment with this stuff by writing a broccoli plugin that converts anonymous blocks to anonymous files (edited) | |
rwjblue [10:21 AM] | |
joined #topic-forms | |
rwjblue [10:21 AM] | |
is this thing on? | |
locks [10:21 AM] | |
mic check | |
machty [10:21 AM] | |
i really want to make a proof of concept of the "component-centric" slots syntax | |
[10:21] | |
since i think i've only succeeded in convincing myself | |
[10:22] | |
but hacking that into broccoli *might* be easier? | |
mmun [10:22 AM] | |
i strongly suspect you’ll be able to hack the compiled templates | |
[10:22] | |
blocks are already first class objects in the runtime. they are even references | |
[10:22] | |
in the same way `foo.bar` is a PathReference | |
machty [10:23 AM] | |
hmm | |
mmun [10:23 AM] | |
hm, at least that used to be true. I could have sworn there was something called a BlockReference | |
machty [10:23 AM] | |
i don't think _I_ have enough context to knock that out | |
mmun [10:27 AM] | |
k i’ll try and hack something | |
machty [10:34 AM] | |
fudge | |
[10:34] | |
i was wrong about making this work with a broccoli hack | |
[10:34] | |
for obviously reasons in hindsight | |
[10:35] | |
it's gotta be at the glimmer layer | |
[10:35] | |
capturing blocks/scope | |
mmun [10:38 AM] | |
hm, blocks aren’t first class values at the compiled template level (edited) | |
machty [10:46 AM] | |
what are they? | |
mmun [10:57 AM] | |
Hard to explain but tldr there is two slots baked in for main/inverse blocks | |
[10:58] | |
Theres atill hope. It will just be a bit trickier | |
machty [11:03 AM] | |
i'd like to discuss component-centric slot syntax further with anyone interested | |
mmun [11:07 AM] | |
The table/column usecase is important to me | |
[11:08] | |
I will try and come up with a more complex example where slots might break down. | |
[11:08] | |
:airplane_departure: | |
machty [11:08 AM] | |
you want an API for you use "slots" to essentially define the schema of the table? | |
mmun [11:09 AM] | |
I want to define header/main/footer cells for each column (edited) | |
[11:09] | |
And not worry about doing an each loop myself | |
[11:10] | |
Cuz then it can use smoke and mirrors under the hood or whatever (edited) | |
machty [11:12 AM] | |
smoke-and-mirrors the addon? | |
mmun [11:12 AM] | |
Yeah | |
[11:12] | |
In case your table is very large | |
[11:13] | |
Its not an actual problem i have atm but i believe that sort of abstraction should be possible... | |
[11:14] | |
In react the solutions are very clear for this :p | |
[11:15] | |
You could just pass an array of { headerComponentClass, bodyComponentclas, footerComponentclas } | |
[11:16] | |
Same is true in ember i guess | |
[11:17] | |
The issue is just that the extra files are annoyong i suppose | |
[11:17] | |
I tgibk i see what you mean. Taking off now | |
machty [11:22 AM] | |
JSX elegantly weaves in and out of JS/JSX nesting | |
[11:23] | |
which makes it easy to express all of those cases | |
[11:24] | |
the inability to weave in and out of {{}}/DOM syntax screws us over (edited) | |
[11:26] | |
`{{x-foo template=(|foo| <div>Hello I am {{foo.title}}</div>)}}` | |
[11:27] | |
in JSX it's | |
[11:27] | |
```<XFoo template={ foo => { | |
return <div>Hello I am { foo.title }</div>; | |
} }/> | |
``` | |
[11:27] | |
can't say it's beautiful but it works today and according to "Just JS™" rules that everyone understands | |
[11:28] | |
if you wanted to pass in arrays of { headerComponentClass, bodyComponentclas, footerComponentclass }: | |
[11:30] | |
```<XTable columns={ [ | |
{ | |
header: data => <span>{ data.wat }</span>, | |
body: data => <span>{ data.wat }</span>, | |
footer: data => <span>{ data.wat }</span>, | |
}, | |
{ | |
header: data => <span>{ data.wat }</span>, | |
body: data => <span>{ data.wat }</span>, | |
footer: data => <span>{ data.wat }</span>, | |
}, | |
{ | |
header: data => <span>{ data.wat }</span>, | |
body: data => <span>{ data.wat }</span>, | |
footer: data => <span>{ data.wat }</span>, | |
}, | |
] }/> | |
``` | |
machty [11:34 AM] | |
uploaded this image: Pasted image at 2017-01-18, 11:34 AM | |
Add Comment | |
cowboyd [11:34 AM] | |
yep. This is why I feel that hbs has got to evolve some pretty big superpowers in order to remain a compelling alternative. “Separation of logic” is not an end unto itself. | |
locks [11:34 AM] | |
hbs isn't exactly about separation of logic | |
cowboyd [11:36 AM] | |
https://media.giphy.com/media/ljaDzjv8cpIpa/giphy.gif (Not automatically expanded because 10MB is too large. You can expand it anyway or open it in a new window.) | |
[11:36] | |
(agree) | |
[11:37] | |
100% | |
[11:38] | |
But I think there is a large conception that "separation of logic" is an end unto itself and I think its harming handlebars’ prospects. | |
[11:38] | |
I think “elimination of side-effects” is a worthy goal | |
[11:39] | |
but so many of the scars that we all got from ERB and liquid templates, can’t happen in handlebars because of the way it’s built. | |
machty [11:39 AM] | |
yeah | |
[11:39] | |
that JSX template is side-effect free (edited) | |
[11:40] | |
i feel like there _should_ be a way to represent that in HBS | |
cowboyd [11:41 AM] | |
and furthermore, experimenting with different approaches shouldn’t require changes to the compiler. | |
[11:42] | |
JSX can do this because it has a way to express simple abstractions. | |
machty [11:42 AM] | |
glimmer capitalizes on efficient rerendering of the known-to-be-static bits | |
[11:43] | |
+ the ability to know which piece of data changed | |
[11:43] | |
which further narrows down the computations involved to figure out what changed / what needs to be re-rendered | |
[11:43] | |
Inferno JSX already does the first part of that | |
[11:44] | |
JSX is "just JS" but you can still parse a JSX template and tell what the static bits are | |
[11:44] | |
so it's not like that's a feature unique to the handlebars syntax | |
[11:45] | |
man | |
[11:45] | |
there are so many crappy strawman arguments against JSX | |
samselikoff [11:46 AM] | |
its hard to take an unbiased look at everything | |
[11:47] | |
could you have done glimmer rewrite with jsx? Did hbs give them certain guarantees that made it possible to do that? I mean that was a big win for a lot of apps | |
machty [11:49 AM] | |
i don't think anyone's suggesting it should have been on top of jsx | |
machty [11:51 AM] | |
added this Plain Text snippet: nested handlebars syntax? | |
curly style | |
{{x-table columns={{ (array | |
(hash | |
header=(|data| <span>{{data.wat}}</span>) | |
body=(|data| <span>{{data.wat}}</span>) | |
footer=(|data| <span>{{data.wat}}</span>) | |
) | |
(hash | |
header=(|data| <span>{{data.wat}}</span>) | |
body=(|data| <span>{{data.wat}}</span>) | |
footer=(|data| <span>{{data.wat}}</span>) | |
) | |
(hash | |
header=(|data| <span>{{data.wat}}</span>) | |
body=(|data| <span>{{data.wat}}</span>) | |
footer=(|data| <span>{{data.wat}}</span>) | |
) | |
) }} }} | |
or glimmer style: | |
<x-table columns={{ (array | |
(hash | |
header=(|data| <span>{{data.wat}}</span>) | |
body=(|data| <span>{{data.wat}}</span>) | |
footer=(|data| <span>{{data.wat}}</span>) | |
) | |
(hash | |
header=(|data| <span>{{data.wat}}</span>) | |
body=(|data| <span>{{data.wat}}</span>) | |
footer=(|data| <span>{{data.wat}}</span>) | |
) | |
(hash | |
header=(|data| <span>{{data.wat}}</span>) | |
body=(|data| <span>{{data.wat}}</span>) | |
footer=(|data| <span>{{data.wat}}</span>) | |
) | |
) }} /> | |
Add Comment Collapse | |
cowboyd [11:52 AM] | |
@machty I like the idea of `(|x| )` for lambda abstraction over values, `{|x| }` for lambda abstraction over DOM (edited) | |
machty [11:53 AM] | |
added this Plain Text snippet: with [] and (key=value) array/hash literals | |
<x-table columns={{ [ | |
( header=(|data| <span>{{data.wat}}</span>) | |
body=(|data| <span>{{data.wat}}</span>) | |
footer=(|data| <span>{{data.wat}}</span>) | |
) | |
( header=(|data| <span>{{data.wat}}</span>) | |
body=(|data| <span>{{data.wat}}</span>) | |
footer=(|data| <span>{{data.wat}}</span>) | |
) | |
( header=(|data| <span>{{data.wat}}</span>) | |
body=(|data| <span>{{data.wat}}</span>) | |
footer=(|data| <span>{{data.wat}}</span>) | |
) | |
] }} /> | |
Add Comment Collapse | |
cowboyd [11:53 AM] | |
`header={|data| <span>{{data.wat}}</span>}` | |
machty [11:53 AM] | |
@cowboyd interesting... | |
[11:56] | |
that would mean `<x-foo someDom={{{hey i am a text fragment}}}/>` | |
cowboyd [11:57 AM] | |
Yeah, or `<x-foo someDom={{{|| hey i am a text fragment}}}/>` | |
[11:57] | |
I guess it wouldn’t be ambiguous, I think @mmun has thoughts on this. | |
locks [11:59 AM] | |
dear god | |
machty [12:00 PM] | |
@locks tellme | |
locks [12:01 PM] | |
just general change anxiety | |
samselikoff [12:01 PM] | |
it is a lot | |
cowboyd [12:01 PM] | |
but it is actually so little | |
locks [12:01 PM] | |
seems very pro-oriented | |
cowboyd [12:02 PM] | |
JSX: pro-oriented? | |
samselikoff [12:02 PM] | |
(not really fair for me to comment, ive been in and out of the convo) | |
cowboyd [12:02 PM] | |
totes fair | |
[12:02] | |
all is fair in love and Ember | |
locks [12:02 PM] | |
@samselikoff that hasn't stopped me :troll: | |
machty [12:03 PM] | |
here's the thing, cowbody and i post our hamstrung syntaxes that look like terse pro-user features, but what's missing are the comparisons with today's solutions involving multiple files and passing of attrs / data that would be elegantly solved by having a lambda syntax | |
[12:04] | |
:cow: | |
samselikoff [12:04 PM] | |
yes | |
[12:04] | |
would be great to have a single use case that's really hard right now | |
[12:05] | |
well there's a lot going on in the convo right. one is js/hbs split for simple things, and if that's good or bad | |
[12:05] | |
other is, missing primtiives that make certain things hard/difficult | |
[12:06] | |
ryan and i were talking yesterday. is `{{let hasStatus=(bool user.status)}}` better than `hasStatus: Ember.computed.bool('user.status')` | |
[12:06] | |
```{{let isOpen=(eq a b)}} | |
{{let isNew=(eq c d)}} | |
{{let isActive=(and isOpen isNew)}} | |
... | |
<a class={{if isActive 'active'}}>Foo</a> | |
``` | |
[12:07] | |
i think this is one piece of the convo. whether the split is better or worse | |
cowboyd [12:08 PM] | |
https://embercommunity.slack.com/archives/topic-forms/p1484759175001848 | |
We all know where I stand on the matter :slightly_smiling_face: | |
samselikoff | |
ryan and i were talking yesterday. is `{{let hasStatus=(bool user.status)}}` better than `hasStatus: Ember.computed.bool('user.status')` | |
Posted in #topic-formsToday at 12:06 PM | |
samselikoff [12:08 PM] | |
:slightly_smiling_face: | |
[12:08] | |
well once the truth helpers came, I mean | |
[12:08] | |
`{{if (eq a b) 'active'}}` | |
rwjblue [12:08 PM] | |
btw, @cowboyd thank you for writing the RFC :slightly_smiling_face: | |
samselikoff [12:08 PM] | |
I do this all the time now. I think its better | |
[12:08] | |
what about `(eq (or (and a b) (and c d)))`? idk | |
cowboyd [12:09 PM] | |
that’s why you need let ^^ | |
samselikoff [12:09 PM] | |
and once it gets to that point, should it be at top of hbs template like ^ or moved to a JS CP | |
rwjblue [12:09 PM] | |
aye, giving it a name makes it much much better | |
[12:09] | |
and basically no different than JS CP (IMO) | |
[12:10] | |
the only reason it is better in JS is that you get to give it a name | |
[12:10] | |
and `let` lets you do that just fine | |
[12:10] | |
(pun intended) | |
cowboyd [12:10 PM] | |
```{{let x=(and a b) y=(and c d)}} | |
<div attr={{or x y}}></div> | |
``` | |
(edited) | |
[12:10] | |
@samselikoff see how a dragon becomes a teddy bear ^^ | |
samselikoff [12:10 PM] | |
hehe | |
locks [12:10 PM] | |
that's literally code from your projects isn't it | |
samselikoff [12:11 PM] | |
is this harder for newbies, like now they have to learn good programming practices in nearly two languages | |
locks [12:11 PM] | |
they already did | |
samselikoff [12:11 PM] | |
is it harder for designers looking at templates? (does that matter?) | |
locks [12:11 PM] | |
that's a trick question | |
[12:11] | |
it matters :P | |
samselikoff [12:12 PM] | |
also if all these constructs are more for lib authors than app developers | |
[12:12] | |
i mean i work mostly with app developers. the mistakes their making are nowhere near this stuff you know | |
[12:12] | |
none of the programmers ive mentored have said "you know i really need a lambda in my template" | |
cowboyd [12:13 PM] | |
I bet they have | |
[12:13] | |
although they did not express it in that way | |
[12:13] | |
You wouldn’t teach JSX without functions, and people manage to learn it somehow. | |
[12:14] | |
This is programming, and no matter where you run, the need for functions will find you. | |
locks [12:14 PM] | |
you cna't function otherwise | |
cowboyd [12:14 PM] | |
:tophat: | |
machty [12:15 PM] | |
added this Plain Text snippet: nested DOM/hbs syntax and slots | |
If we were able to infinitely nest HBS/DOM syntax (like you can in JSX), then we wouldn't even need to define a proprietary new syntax specific to "slots" or "named yields". | |
<x-foo slots={{ (hash | |
header=(|data| <h1>{{data.foo}}</h1>) | |
body=(|data| <h1>{{data.foo}}</h1>) | |
footer=(|data| <h1>{{data.foo}}</h1>) | |
) }} /> | |
Add Comment Collapse | |
machty [12:16 PM] | |
also I believe Yehuda proposed a _similarish_ strawman syntax to @mmun not long ago... | |
cowboyd [12:17 PM] | |
I still think you need different syntax for values and DOM | |
machty [12:19 PM] | |
that's fine, i'd file that under bikeshed though | |
cowboyd [12:19 PM] | |
yeah, don’t want to detract from your point which is a fine one :slightly_smiling_face: (edited) | |
machty [12:19 PM] | |
mostly just want to convince people that JSX works for a reason | |
[12:19] | |
n00bs understand JSX | |
[12:19] | |
React has proven this | |
cowboyd [12:20 PM] | |
truth | |
[12:21] | |
Because you end up having to teach _less_ in the long run | |
[12:22] | |
as you need less one-off mechanisms to address specific use-cases | |
samselikoff [12:22 PM] | |
> as you need less one-off mechanisms to address specific use-cases | |
i can totally buy this | |
machty [12:23 PM] | |
slot syntax is a scenario solve | |
cowboyd [12:31 PM] | |
block re-use comes for free: | |
```{{let header=(|data| {{data.foo}})}} | |
<x-foo mode=x header=header> | |
<x-foo mode=y header=header> | |
<x-foo mode=z header=header> | |
``` | |
locks [12:32 PM] | |
when is `data` captured? | |
cowboyd [12:32 PM] | |
when `x-foo` yields to it | |
locks [12:33 PM] | |
inside x-foo `{{header pieceOfData}}`? | |
cowboyd [12:33 PM] | |
yuh-huh | |
locks [12:34 PM] | |
ok, it doesn't capture from outer scope? | |
cowboyd [12:34 PM] | |
it does, | |
locks [12:35 PM] | |
hm. | |
cowboyd [12:37 PM] | |
I’m sure what exactly was “captured” would be up for no small amount of discussion, but I’d expect: | |
```{{let header=(|data| {{this.name}} {{data.foo}})}} | |
<x-foo mode=x header=header> | |
<x-foo mode=y header=header> | |
<x-foo mode=z header=header> | |
``` | |
to work | |
[12:38] | |
or maybe you exclude dynamic scope and only capture lexical scope | |
[12:38] | |
```{{let name=this.name}} | |
{{let header=(|data| {{name}} {{data.foo}})}} | |
<x-foo mode=x header=header> | |
<x-foo mode=y header=header> | |
<x-foo mode=z header=header> | |
``` | |
mmun [12:41 PM] | |
I use let when i have multiple moment-format that i want to format the same way in a single template | |
machty [12:42 PM] | |
@cowboyd what is `{{this.name}}` even referring to? (edited) | |
mmun [12:42 PM] | |
{{let dateFormat="DD YYYY"}} | |
[12:43] | |
Btw love everything machty and cowbody are putting down in the last hour | |
cowboyd [12:46 PM] | |
@machty YIL https://embercommunity.slack.com/archives/topic-forms/p1484683316001513 | |
cowboyd | |
Like in your twiddle, you used `this.person` I wasn’t aware that was a thing. | |
Posted in #topic-formsYesterday at 3:01 PM | |
machty [12:46 PM] | |
ah | |
[12:46] | |
tie-breaker | |
[12:46] | |
yeah i definitely think lexical is the way to go | |
[12:47] | |
it behaves the same as if you moved the contents outside of that anonymous block | |
[12:47] | |
(other than the missing block param) | |
[12:48] | |
this wins an award https://embercommunity.slack.com/archives/topic-forms/p1484760663001900 | |
cowboyd | |
block re-use comes for free: | |
```{{let header=(|data| {{data.foo}})}} | |
``` | |
Show more… | |
Posted in #topic-formsToday at 12:31 PM | |
[12:49] | |
i want this so bad | |
[12:49] | |
i'm going to cry if it hits a dead end and we end up shipping toys for noobs instead | |
cowboyd [12:50 PM] | |
me too | |
machty [12:52 PM] | |
i think glimmer/hbs syntax has conceptual integrity to it | |
[12:52] | |
it's a declarative syntax | |
[12:53] | |
that makes it possible for the rendering engine to understand where data is changing | |
[12:53] | |
in a way that wouldn't be possible with JSX | |
[12:53] | |
and we should make it as awesome as it should be within those bounds | |
samselikoff [12:54 PM] | |
youre saying that block/lambda doesn't go outside of those bounds, bc you can't do anything you want within the body of the lambda? | |
machty [12:55 PM] | |
you can't do anything side-effecty / nondeclarative period, and introducing lambda syntax doesn't violate that in any way | |
samselikoff [12:55 PM] | |
```{{let header=(|data| {{ Ember.run.scheduleOnce }})}} | |
``` | |
[12:55] | |
right | |
machty [12:55 PM] | |
i don't want that | |
[12:55] | |
we can consider opening that door in a separate RFC | |
samselikoff [12:55 PM] | |
right your mental model there is still, declarative transforms | |
[12:55] | |
i see how block/lambba doesnt really change that | |
machty [12:56 PM] | |
yeah | |
samselikoff [12:56 PM] | |
basically, when your writing your templates | |
[12:56] | |
and you need to jump back to JS just to do CPs | |
[12:56] | |
95% of hte time you're trying to transform data | |
[12:56] | |
"massage" as they say, into a form suitable for your ui | |
machty [12:57 PM] | |
we had some other examples the other day where lambda syntax could actually replace a lot of one-off helpers | |
samselikoff [12:57 PM] | |
if you could keep that stuff in hbs, could be an improvement | |
[12:57] | |
(whereas, some complicated polling task that happens on component init, maybe more suitable for a JS function?) | |
machty [12:58 PM] | |
yeah | |
[12:58] | |
for sure | |
[12:58] | |
nothing about today's insights make me want to move EC / state mgmt stuff into the template | |
[12:58] | |
(though @cowboyd's microstates gets close to that arena) | |
cowboyd [1:02 PM] | |
microstates is just about using type information to infer the implicit actions for a piece of data | |
[1:03] | |
the state management is still handled in JS | |
[1:03] | |
but you can declaratively map events to _transitions_ in hbs (edited) | |
machty [1:04 PM] | |
gotcha | |
new messages | |
cowboyd [1:06 PM] | |
for reference: https://github.com/cowboyd/ember-microstates | |
machty [1:04 PM] | |
gotcha | |
cowboyd [1:06 PM] | |
for reference: https://github.com/cowboyd/ember-microstates | |
machty [1:10 PM] | |
set the channel topic: poorly named room to discuss (possibly missing) patterns of composition in Ember. Backlog manually persisted here: | |
https://gist.github.com/machty/68afad4c03109f36d4f4cffaae3c170b | |
mmun [1:11 PM] | |
declarative-all-the-things is a pretty big step. i would probably just move to elm or something functional (edited) | |
[1:11] | |
declarative templates isn't | |
[1:14] | |
@cowboyd: i assume you mean `<x-foo mode=x header={{header}}>` and not `<x-foo mode=x header=header>` | |
cowboyd [1:14 PM] | |
yes | |
[1:15] | |
I’d mean `x` to be a variable too. | |
mmun [1:15 PM] | |
a while ago yehuda was musing with me if we could get away with `<x-foo mode=x header={header}>` :stuck_out_tongue: | |
[1:15] | |
double curlies is so heavy :’( | |
cowboyd [1:31 PM] | |
Congratulations everybody! I think we’re officially back on topic if we re-parse `forms` to mean syntactic forms. | |
locks [1:31 PM] | |
forms of programming | |
[1:32] | |
why aren't we in #topic-architecture again? :P | |
cowboyd [1:33 PM] | |
inertia, momentum, or both. | |
mmun [1:33 PM] | |
lol | |
machty [1:35 PM] | |
topic-architecture is too open ended | |
[1:36] | |
i think we all realized there was some fundamental missing stuff related to forms/composability/higher order components | |
[1:37] | |
i think i'm bout ready to yank my let-block rfc | |
[1:37] | |
in favor of nested DOM/block/lambda RFC in conjunction w inline-let RFC | |
mmun [1:41 PM] | |
for the | |
*VERY* | |
ambitious | |
locks [1:41 PM] | |
fcp let | |
[1:42] | |
I'll deprecate with (sorry @lolmaus) | |
[1:42] | |
and we take over ember with our lispiness | |
cowboyd [1:42 PM] | |
*LoL* | |
let over lambda is all you ever need | |
locks [1:42 PM] | |
"shtop in the name ov lishp" | |
machty [1:43 PM] | |
that's more sean connery's speech impediment | |
mmun [1:43 PM] | |
the `let` rfc needs a little more time to :stew: (edited) | |
locks [1:43 PM] | |
doubt we have consensus anyway :P | |
machty [1:44 PM] | |
nested DOM/block/lambda syntax ain't dependent on it. can use `#with` or `ember-let` (edited) | |
locks [1:44 PM] | |
did we agree on erroring for multiple declarations of same var in same scope? | |
cowboyd [1:44 PM] | |
yup. | |
mmun [1:45 PM] | |
I am OK with that rule. | |
[1:45] | |
It should not come often in practice anyways. | |
locks [1:45 PM] | |
and the binding is only accessible from the declaration downwards? (aka, my last in-thread comment is correct) | |
mmun [1:46 PM] | |
We can also suggest a refactoring (in the RFC): If you _really_ want to bind the same name twice, then make the lifetime of the name explicit by using a let-block | |
locks [1:47 PM] | |
yy | |
[1:47] | |
and if you want to nest, it shadows | |
[1:48] | |
what about derived bindings? | |
[1:48] | |
`+{{let* a=1 b=(sum a 5)}} <!-- `b`'s binding expression sees `a` -->` in the rfc | |
[1:49] | |
```{{let a=1}} | |
{{let b=(sum a 5)}} | |
``` | |
? | |
mmun [1:49 PM] | |
I don't know. It may be helpful to grep some clojure codebases to get a sense of how common it is | |
[1:50] | |
Personally I think it's fine to additionally support `let*`, but I don't want to complicate getting inline-let merged :stuck_out_tongue: (edited) | |
locks [1:50 PM] | |
I think I use it in what little clj code I have :joy: | |
[1:51] | |
not sure I'm comfortable with that semantic change post-doc | |
mmun [1:51 PM] | |
that is not an option | |
[1:51] | |
we don't break userspace! | |
machty [1:51 PM] | |
it (derived/serial bindings) is extremely common in clj (edited) | |
miguelcobain [1:52 PM] | |
joined #topic-forms | |
mmun [1:52 PM] | |
let should absolutely have clj-let semantics. | |
locks [1:52 PM] | |
oohh, you mean literally `let*` | |
mmun [1:52 PM] | |
yes | |
cowboyd [1:53 PM] | |
`let*` would just be another transform of block `let` | |
mmun [1:53 PM] | |
originally I implemented ember-let as let* (not knowing about let & let* in clj), but Charles convinced me otherwise. | |
locks [1:53 PM] | |
can't find `let*` in clj docs | |
machty [1:53 PM] | |
i don't think `let*` is clojure | |
locks [1:53 PM] | |
ok | |
[1:54] | |
clj-let just has those semantics already | |
cowboyd [1:54 PM] | |
it’s in scheme, CL and elisp | |
machty [1:54 PM] | |
the clj syntax is `(let [x 'xValue' y 'yValue'] ...)` | |
[1:54] | |
if you wanna binding one thing just do `(let [x 'xValue'] ...)` | |
locks [1:54 PM] | |
hey, if we're going down this road we should go for broke :P | |
mmun [1:54 PM] | |
well, I'll let @cowboyd make the argument (edited) | |
cowboyd [1:55 PM] | |
@machty `let*` is a bout sequential vs parallel binding | |
mmun [1:55 PM] | |
`{{let a=1 a=(mul a a)}}` | |
machty [1:55 PM] | |
when would they ever behave differently? | |
mmun [1:55 PM] | |
^ that is a weird thing to do in hbs | |
[1:56] | |
can you do that in CL? (define the same name twice) (edited) | |
machty [1:56 PM] | |
```user=> (let [a 2 a (* a a)] a) | |
4 | |
``` | |
mmun [1:56 PM] | |
i c | |
locks [1:57 PM] | |
www.tryclj.com for future discussions | |
cowboyd [1:57 PM] | |
So Clojure is `let*` all day (edited) | |
locks [1:57 PM] | |
c | |
cowboyd [2:04 PM] | |
Same example in scheme: | |
```scheme@(guile-user)> (let ((a 1) (a (* a 2))) a) | |
;;; <stdin>:6:15: warning: possibly unbound variable `a' | |
<unnamed port>:6:0: In procedure #<procedure 107f5fb80 at <current input>:6:0 ()>: | |
<unnamed port>:6:0: In procedure module-lookup: Unbound variable: a | |
Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. | |
scheme@(guile-user) [1]> (let* ((a 1) (b (* a 2))) b) | |
$3 = 2 | |
scheme@(guile-user) [1]> (let* ((a 1) (a (* a 2))) a) | |
$4 = 2 | |
scheme@(guile-user) [1]> | |
``` | |
mmun [2:07 PM] | |
```(defun foo (a b) | |
(let ((a (max a b)) | |
(b (min a b))) | |
``` | |
[2:08] | |
that is totally something i've done in rust | |
[2:08] | |
`let (a, b) = (min(a,b), max(a,b));` | |
[2:09] | |
while let* can be convenient I ultimately think we should use the weaker construct | |
knownasilya [2:11 PM] | |
joined #topic-forms | |
knownasilya [2:12 PM] | |
@machty what's the alternative to your RFC? | |
machty [2:15 PM] | |
@knownasilya something like this https://embercommunity.slack.com/archives/topic-forms/p1484760663001900 | |
cowboyd | |
block re-use comes for free: | |
```{{let header=(|data| {{data.foo}})}} | |
``` | |
Show more… | |
Posted in #topic-formsToday at 12:31 PM | |
[2:15] | |
glimmer syntax that allows zipping in and out of glimmer/dom syntax | |
[2:15] | |
so that we can pass in things as attrs | |
machty [2:20 PM] | |
so i'm gonna go ahead and talk about "component-centric slots" in the context of these new ideas | |
[2:20] | |
because i think it's an opportunity for conventions and structure that ember can provide where other frameworks might lack (edited) | |
knownasilya [2:27 PM] | |
sweet. | |
[2:27] | |
I'm not a fan of the syntax, but that's secondary | |
lukemelia [2:33 PM] | |
joined #topic-forms | |
machty [2:35 PM] | |
player 2 has entered the game | |
machty [2:48 PM] | |
ok, well i'm stuck again so i'll share my thought process | |
machty [2:49 PM] | |
added this Markdown (raw) snippet | |
Here's a component that renders components passed into it. | |
Due to today's limitations, these components have to live in | |
separate files, and any data that those components need to | |
do their job must be explicitly passed in (e.g. x y and z). | |
| |
```hbs | |
{{x-foo | |
header=(component 'x-header' data=(hash x=x y=y z=z)) | |
body=(component 'x-body' data=(hash x=x y=y z=z)) | |
footer=(component 'x-footer' data=(hash x=x y=y z=z)) | |
}} | |
``` | |
| |
This implies that `x-foo`'s layout template was using the | |
`{{component}}` helper to render these components-passed-as-attrs: | |
| |
```hbs | |
{{! x-foo's layout template }} | |
| |
{{component header bar=123}} | |
{{component body bar=123}} | |
{{component footer bar=123}} | |
``` | |
| |
Let's say we add some JSX-style syntax where we make easy | |
to pass in a template block as an attr. Let's just start | |
with `footer` for now (actual syntax for inline template | |
blocks is in bikeshed territory outside the point I'm trying | |
to make): | |
| |
```hbs | |
{{x-foo | |
header=(component 'x-header' data=(hash x=x y=y z=z)) | |
body=(component 'x-body' data=(hash x=x y=y z=z)) | |
| |
footer=(|data| | |
<p> | |
I used to have to live in another file but | |
now I can just live here! Yay! | |
| |
{{x}} {{y}} {{z}} | |
| |
Look ma, no excessive attr passing! | |
I work just like classic blocks that | |
close over the current scope! | |
| |
What about data passed in from x-foo? | |
How about: {{data.bar}} | |
</p> | |
) | |
}} | |
``` | |
Add Comment Collapse | |
dfreeman [2:49 PM] | |
joined #topic-forms | |
machty [2:50 PM] | |
questions / comments on the above: | |
[2:51] | |
1. It'd be awesome if the above refactor didn't require making any changes to `x-foo`; what used to be renderable with `{{component attrName}}` is still renderable with `{{component attrName}}` | |
[2:51] | |
2. But since it's still rendering with `{{component}}`, should it be wrapped in a tag, or should there be implicit `tagName: ''`? | |
[2:53] | |
3. What is `|data|`? It _could_ just be a hash of merged attrs, OR we could consider it just making it the anonymous instance of Ember.Component that's rendering that template block, in which case it'd still represent the merged hash of attrs and be consistent with the classic `{{component}}` API | |
mmun [2:54 PM] | |
I disagree with the premise | |
[2:54] | |
And sorry for drive by pooping... About to take off again | |
machty [2:55 PM] | |
4. The reason I don't want to just extend the `{{yield}}` API here (to allow you to just `{{yield a b c to=someBlockAttr}}` is that we'd be fragmenting the world between things that accept an attr hash (components) and things that render with positional params (yield) | |
mmun [2:56 PM] | |
Agreed. If anyrhing block sbould be coercible to component | |
machty [2:56 PM] | |
If we extended yield. then we couldn't support swapping between `attr=(component 'x-footer')` and `attr=(|data| <div></div>)` | |
mmun [2:56 PM] | |
And invokable via {{component}} | |
machty [2:58 PM] | |
@mmun but would we still support `{{yield a b c to=someBlockAttr}}` ? | |
mmun [2:58 PM] | |
Unclear. | |
[2:58] | |
Also i would expect the block argument to be attrs but i think we agree there | |
machty [2:58 PM] | |
if you do, then we'll have to explain to the world when/why you'd write a component whose API either expected blocks with `|data|` or blocks with `|positional params|` | |
cowboyd [2:59 PM] | |
wouldn’t it make the most sense to have blocks just take attrs too? | |
[2:59] | |
`{|a b c= d=| {{a}} {{b}} {{c}} {{d}}}` (edited) | |
mmun [2:59 PM] | |
Yes | |
[3:00] | |
Its confusing syntax thoug | |
machty [3:00 PM] | |
keep in mind the ideal goal of being able to quickly switch `attr=(component 'x-footer')` and `attr=(|data| <div></div>)`, back and forth | |
mmun [3:00 PM] | |
You need to choose a local binding name (edited) | |
machty [3:00 PM] | |
and if you make it easy/possible/common to yield with positional params, then you can 't do that without dipping into esoteric `positionalParams` API | |
mmun [3:01 PM] | |
Import { foo } vs import { foo as bar } | |
[3:01] | |
Machty you raise good points. I will ponder it | |
machty [3:01 PM] | |
additionally, it's not uncommon to for a component like `x-foo` to forward its component-y attrs to yet another component, so THAT component would also need to agree on the API | |
mmun [3:02 PM] | |
There is a simple solution to just go all in with lambdas | |
cowboyd [3:02 PM] | |
remind me why simplying saying `{{attr data name='value'}}` (inside body of x-foo) doesn’t work again? I feel like I keep asking the same question. (edited) | |
machty [3:03 PM] | |
because what is `data` when you go back to using `attr=(component 'x-foo')` | |
[3:03] | |
how does `x-foo` access it without using `positionalParams` api | |
mmun [3:04 PM] | |
`attr=(|data| {{x-footer ...=data}})` | |
machty [3:05 PM] | |
so we should name that solution "write your own translation layer whenever you want to use `{{yield}}`" | |
mmun [3:06 PM] | |
Catchy | |
machty [3:06 PM] | |
i predict Translation Layers Everywhere if we open that pandoras box | |
[3:06] | |
lol | |
[3:06] | |
hahaha | |
[3:07] | |
wherein machty fails to out-pedantic mmun | |
[3:08] | |
but anyway, yeah, that's my hunch. if we open that pandora's box, then people will have to write these anonymous blocks to translate between something that wants to yield positional params vs pass named attrs | |
[3:08] | |
and sure you could probably conceive of some helper/component to aid in that translation | |
mmun [3:08 PM] | |
Yeah | |
machty [3:08 PM] | |
(but that sucks) | |
cowboyd [3:13 PM] | |
so if I understand: a block could be easily made to masquerade as a component, but not vice-versa, so we want to shoot for the lowest common denominator for yielding, which is the `{{component}}` api. | |
[3:13] | |
i.e. named parameters only. | |
[3:16] | |
slight, but potentially unifying scope creep would be to beef up positional parameters for a component to make them low-friction | |
[3:16] | |
seems like you want two things: the ability to access them in a conventional way without having to explicitly declaring the mapping in your `.js` file | |
[3:17] | |
so that you can use them in your templates and from js | |
machty [3:17 PM] | |
yeah, not to mention i don't think lots of people should have to know about positionalParams, AND the api for it is weird (you have to reopenClass) | |
[3:18] | |
i really don't think the benefits are worth beefing up pos params syntax (edited) | |
cowboyd [3:18 PM] | |
the benefit is that you now have parity between the component-centric and block-centric apis | |
[3:19] | |
which means from the perspective of composition, 1 mental model instead of 2 | |
[3:19] | |
which seems pretty huge, unless I’m missing something. | |
machty [3:19 PM] | |
yeah | |
[3:20] | |
i think we're on the same page | |
[3:20] | |
unfortunately, there are 2 mental models today | |
[3:20] | |
{{yield}} and {{component}} | |
[3:20] | |
i just want to standardize on one | |
[3:20] | |
if one should be a relic of the past, it should be yield | |
[3:21] | |
i made this point in a separate room, but i think JSX has this weakness; when you nest elements, it sets `this.children` prop on the component | |
[3:21] | |
but once you wanna passed multiple named "blocks", you no longer use `this.children` | |
[3:22] | |
you use something that "feels" a little different | |
[3:22] | |
(this is a minor / weak point; just wanted to highlight that it's not specific to ember/component/yield) | |
cowboyd [3:27 PM] | |
So you would rather see the complete external/internal scenario like this: | |
anonymous block | |
```{{let header=(|data=| {{data.foo}})}} | |
<x-foo mode=x header={{header}}> | |
<x-foo mode=y header={{header}}> | |
<x-foo mode=z header={{header}}> | |
``` | |
external component: | |
```{{let header=(component 'external-header' other-prop="something-else"})}} | |
<x-foo mode=x header={{header}}> | |
<x-foo mode=y header={{header}}> | |
<x-foo mode=z header={{header}}> | |
``` | |
inside `x-foo` template: | |
```{{component header data=(hash foo='bar')}} | |
``` | |
(edited) | |
machty [3:28 PM] | |
correction: `{{component header foo='bar'}}` | |
[3:29] | |
(what's `other-propr`? positional param?) | |
cowboyd [3:30 PM] | |
wait, so the block would get a single positional param which was the attrs passed to the component API? | |
[3:32] | |
I was assuming an extended block param syntax to bind nv pairs | |
machty [3:32 PM] | |
one sec | |
cowboyd [3:32 PM] | |
`{{let header=(|foo=| {{foo}})}}` | |
machty [3:37 PM] | |
yeah | |
[3:38] | |
single positional param of attrs | |
[3:40] | |
i'd be happy to add a destructuring syntax for that | |
[3:41] | |
so i have one last idea to share | |
[3:41] | |
the final piece of the puzzle | |
[3:42] | |
but i'll wait on that | |
cowboyd [3:43 PM] | |
Love the idea of a uniform api. Don’t love it being named `component` since that would officially be a lie. | |
machty [3:43 PM] | |
or is it | |
cowboyd [3:44 PM] | |
I suppose if you wrap it in an anonymous component it wouldn’t be. | |
[3:47] | |
but it still would be a lie from the user’s perspective _unless_ we called them anonymous components instead of anonymous blocks. | |
[3:48] | |
in the expression `{{let header=(|attrs| {{attrs.foo}})}}`, `header` is an anonymous component full stop. | |
machty [3:49 PM] | |
i might be ok with that | |
[3:50] | |
i guess it comes down to whether there's some other non-component-y way to render such a block | |
[3:50] | |
i can't think of one | |
cowboyd [3:50 PM] | |
So what about the case where the component _does_ have positional params? | |
[3:50] | |
oh right, in components, positional params always have to be mapped. | |
[3:51] | |
so you can always render with named params | |
machty [3:52 PM] | |
yeah | |
[3:52] | |
so one big open question that's related to my "final piece of the puzzle" is if/when/whether to allow subclasses of Ember.Component | |
cowboyd [3:53 PM] | |
that’s easy: `(|attrs|->extends(Compo-nant) {{attrs.foo}})` | |
machty [3:54 PM] | |
we've been using `|attrs|` in our examples but it _could_ literally just be a reference to a component instance | |
locks [3:54 PM] | |
jc | |
[3:54] | |
this channel is bad for my health | |
machty [3:54 PM] | |
Keep Calm and Remember Yehuda Proposed Inline Hbs Syntax at One Point | |
locks [3:55 PM] | |
yehuda can be wrong too :troll: | |
cowboyd [3:56 PM] | |
@locks I feel you :slightly_smiling_face: this is the nerd equivalent of fear and loathing in Las Vegas | |
machty [3:56 PM] | |
damn has that excuse worn thin? | |
locks [3:56 PM] | |
btw, I was checking some random ember stuff | |
cowboyd [3:57 PM] | |
but it’s good for you in the long run | |
locks [3:57 PM] | |
and I saw something from you telling someone else to not worry about query params, that they were moving to the route soon | |
machty [3:57 PM] | |
i said that? | |
locks [3:57 PM] | |
yeah | |
[3:57] | |
on the blog comments | |
machty [3:57 PM] | |
i wouldn't be surprised if i did | |
[3:57] | |
oh to the route | |
[3:57] | |
i thought they were | |
locks [3:58 PM] | |
we all did at one point | |
[3:58] | |
when routable components were months away | |
machty [3:58 PM] | |
(how's this relevant?) | |
locks [3:58 PM] | |
it isn't, I just remembered | |
[3:58] | |
having public records is awesome for spelunking | |
cowboyd [3:58 PM] | |
https://embercommunity.slack.com/archives/topic-forms/p1484772843002157 | |
machty | |
we've been using `|attrs|` in our examples but it _could_ literally just be a reference to a component instance | |
Posted in #topic-formsToday at 3:54 PM | |
[3:59] | |
curious where you were about to go with this ^^ | |
machty [3:59 PM] | |
right | |
[3:59] | |
well first off it's interesting/of note that if we made it a component instance the api would be the same | |
[3:59] | |
just that you might also be able to access properties on component instance (edited) | |
[3:59] | |
which is maybe a smell if it's just Ember.Component | |
[4:00] | |
but if we made it possible to use a component.js class but with BYO template, it'd might be a nice pattern (edited) | |
[4:00] | |
component can expose properties / things / actions / tasks (edited) | |
locks [4:00 PM] | |
container component style? | |
machty [4:00 PM] | |
maybe, is that defined somewhere? | |
cowboyd [4:02 PM] | |
kinda like a template “mixin” ? | |
locks [4:03 PM] | |
in react literature, but I mean a component with just `{{yield …}}` for a template | |
cowboyd [4:03 PM] | |
right. the pattern of having a component whose only job is to present data to sub components. | |
[4:04] | |
@machty How would you specify the component superclass in a template? | |
machty [4:05 PM] | |
```{{media-player | |
tracklist=(|c| | |
<ul> | |
{{#each c.tracks as |t|}} | |
<li class="track">{{t.title}}</li> | |
{{/each}} | |
</ul> | |
<button onclick={{t.togglePlay}}> | |
{{if t.isPlaying 'Pause' 'Play'}} | |
</button> | |
) | |
}} | |
``` | |
[4:05] | |
this _seems_ like a nice API, regardless of whether it's implemented using this approach or not | |
[4:06] | |
(this approach of specify the class but BYO template) | |
[4:06] | |
in this case it'd be up to `media-player` to specify the component.js class | |
[4:06] | |
this is also a la trek style component extendability / overridabilty (edited) | |
cowboyd [4:06 PM] | |
How is this different than: | |
```{{#media-player as |c|}} | |
<ul> | |
{{#each c.tracks as |t|}} | |
<li class="track">{{t.title}}</li> | |
{{/each}} | |
</ul> | |
<button onclick={{t.togglePlay}}> | |
{{if t.isPlaying 'Pause' 'Play'}} | |
</button> | |
{{/media-player}} | |
``` | |
(edited) | |
machty [4:07 PM] | |
it's only different when you selectively override multiple different parts | |
webark [4:07 PM] | |
joined #topic-forms | |
machty [4:07 PM] | |
`{{yield}}` only becomes a crappy API once you need to yield more than one thing | |
cowboyd [4:08 PM] | |
you could even steal a play from ES6 modules’ book. | |
alexander-alvarez [4:08 PM] | |
joined #topic-forms | |
machty [4:08 PM] | |
i guess my example wasn't clear: you're rendering a `media-player`, which renders lots of things, including a tracklist, that you can individually swap out with your own thing | |
cowboyd [4:08 PM] | |
right | |
[4:09] | |
to continue the es6 analogy, you could even say something like `{{yield}}` is equivalent to `{{component default}}` | |
[4:09] | |
not that it’s a requirement, but just trying to rif on the underpinnings of what you’re proposing (edited) | |
machty [4:10 PM] | |
sure, though maybe better to avoid the yield comparisons since then you have to think/talk about positional params | |
[4:10] | |
so anywho | |
[4:10] | |
how might `media-player` render your template with its own built in .js file... | |
new messages | |
cowboyd [4:11 PM] | |
`{{media-player layout=}}`? | |
machty [4:13 PM] | |
hmmm | |
[4:13] | |
is it layout or template? | |
[4:13] | |
(is `template` even overridable anymore?) | |
cowboyd [4:14 PM] | |
shrugs | |
locks [4:14 PM] | |
template is gone | |
machty [4:14 PM] | |
werd | |
[4:14] | |
i think we're getting closer to stuff that can be solved in user-space once the basic features are in place | |
[4:15] | |
it's worth relinking this particular section https://gist.github.com/machty/c00c83f3fbefefa72cefb0bb2322fc4f#x-calendar-layout | |
[4:16] | |
because in all of this jsx-inspired, open-ended / component-y stuff, there are still some reaaaally nice conventions here | |
[4:16] | |
conventions that have been hiding behind present day clunky glimmer/hbs | |
cowboyd [4:24 PM] | |
I actually have to go heads down for a bit.... | |
machty [4:27 PM] | |
same | |
cowboyd [4:28 PM] | |
this channel is addictive tho `:crack-pipe-emoji:` | |
samselikoff [4:58 PM] | |
nerds | |
locks [5:08 PM] | |
https://slackhq.com/threaded-messaging-comes-to-slack-417ffba054bd#.vil1khrdy | |
Several People Are Typing — The Official Slack Blog | |
Threaded messaging comes to Slack | |
Keep conversations organized and easy to follow with Threads | |
Reading time | |
---------------- | |
4 min read | |
(269KB) | |
Yesterday at 1:00 PM | |
[5:08] | |
brain assplosion | |
machty [5:08 PM] | |
saw that too... the buttons haven't shown up for me yet | |
locks [5:10 PM] | |
and thus starts slack's descent | |
samselikoff [5:23 PM] | |
i just saw this today https://risingstars2016.js.org/, and find it interesting wrt this channel's convos. Because vuejs has a template/js separation | |
risingstars2016.js.org | |
2016 JavaScript Rising Stars | |
A complete overview of the JavaScript landscape in 2016: trends about front-end and node.js frameworks, tooling, IDE, Static site generators... (48KB) | |
locks [5:29 PM] | |
they have single file though | |
cowboyd [5:29 PM] | |
Overall, I see template/js separation as a good thing. Just a matter of what goes where. Also, Vue has a great escape hatch when that’s not what you want. | |
locks [5:29 PM] | |
which appeases most people | |
cowboyd [5:29 PM] | |
yeah | |
locks [5:29 PM] | |
and they have veux | |
samselikoff [5:31 PM] | |
what's the escape hatch? | |
[5:31] | |
> they have single file though | |
this wouldn't explain why react devs are switching | |
locks [5:34 PM] | |
one rfc down, muahaha | |
[5:34] | |
@samselikoff sure, they're separate but imo related things | |
machty [5:34 PM] | |
what do you think i'm working on | |
locks [5:35 PM] | |
colocation is enough for most people | |
[5:35] | |
as in, the general concern I see is "I have to have two files open, boo", not "I want JSX" | |
mmun [7:35 PM] | |
I dont share the love for {{component}} | |
[7:36] | |
Block lambdas let you pass fragments | |
[7:38] | |
In react you can pass a component factory as a prop or pass a function that when executed returns dom | |
[7:38] | |
How are people dealing with this dichotomy? | |
[7:39] | |
Or does react support fragment components? | |
machty [7:40 PM] | |
afaik react doesn't yet support fragments? | |
[7:40] | |
https://github.com/facebook/react/issues/2127 | |
mmun [7:40 PM] | |
We should ask ppl in the know | |
machty [7:40 PM] | |
but anywho: if it's a tag-less component, what's the difference? | |
[7:41] | |
(i forget what the plan is for glimmer components, whether they're tagless or how they work at all) | |
mmun [7:41 PM] | |
Yes thats fine for named components (edited) | |
[7:41] | |
But were talking about compositions that only involve one file | |
machty [7:42 PM] | |
yeah | |
[7:42] | |
well it's not clear yet what the value of an anonymous block actually is | |
mmun [7:42 PM] | |
It bugs we that there isnt one obvious solution (edited) | |
machty [7:43 PM] | |
is it some BlockReference or something? | |
[7:43] | |
or maybe it's a tagless component right off the bat (edited) | |
mmun [7:43 PM] | |
With layout simply `{{yield}}` | |
machty [7:44 PM] | |
? | |
mmun [7:45 PM] | |
Bleh. | |
machty [7:46 PM] | |
```{{x-foo | |
thing=(|c| | |
<div> | |
{{c.title}} | |
</div> | |
) | |
}} | |
``` | |
(edited) | |
[7:46] | |
the question "what is `thing`" is up for debate | |
[7:47] | |
one possible answer is it's an Ember.Component with `tagName: ''` | |
[7:47] | |
you render it with `{{component}}` and it'll be a fragment | |
[7:48] | |
if it were `thing=(component 'x-foo')` then it'd defer to x-foo's .js to figure out what it is, or be wrapped in a div by default | |
[7:48] | |
or some default that aligns w glimmer components | |
mmun [8:30 PM] | |
That part i can live with. What is c is the sticky wicket | |
[8:31] | |
If you invoke a block as a component it could be attrs. | |
[8:31] | |
If you invoke it with yield its the regular thing | |
[8:31] | |
Both seem fine | |
machty [8:31 PM] | |
i don't want these to be invocable with yield for the many reasons i laid out above | |
mmun [8:32 PM] | |
You just became my 006 | |
[8:32] | |
Machtrevelyan (edited) | |
machty [8:33 PM] | |
lol what's that mean | |
mmun [8:35 PM] | |
Haha. 006 betrays 007 at the beginning of goldeneye | |
[8:37] | |
I prefer yield and lambdas. You resist because of the indirection introduced when you wrap a component invocation with a lambda | |
[8:38] | |
But in my eyes the component subexpression is just as gnarly | |
machty [8:38 PM] | |
(also because: how do you "forward" your yield+lambda syntax to internal components that expects `(component)`s) (edited) | |
mmun [8:38 PM] | |
Especially when you consider html component invocations | |
machty [8:38 PM] | |
say more | |
mmun [8:39 PM] | |
Ugh hard to type on phone | |
[8:39] | |
In a lambda you can invoke glimmer componnents eith plain html syntax | |
[8:40] | |
Ok sorry im tackling the wrong strawman | |
[8:40] | |
Your suggesting that the lambda syntax is a component | |
[8:41] | |
Is be coolish with that if it plays well with @attrs and doesnt require {{component}} | |
machty [8:41 PM] | |
man | |
[8:41] | |
i'm out of the loop | |
[8:41] | |
what is `@attrs` (and what "stage") (edited) | |
mmun [8:42 PM] | |
<glim-comp @foo="{{bar}}"> | |
[8:43] | |
In yehudaa mind probably stage 2 but no rfc yet (edited) | |
machty [8:43 PM] | |
ok | |
mmun [8:43 PM] | |
Yehudada | |
[8:43] | |
:tm: | |
machty [8:43 PM] | |
my spider sense tells me i'm going to want to flip tables at the end of how many constraints are imposed by new untested glimmer syntax | |
mmun [8:44 PM] | |
@ have a very legit purpose | |
[8:44] | |
For html integration | |
machty [8:44 PM] | |
ah ok | |
locks [8:44 PM] | |
I think `@` is pretty solidly here | |
[8:44] | |
regardless of actual sigil | |
mmun [8:45 PM] | |
Sorry. We call them args now. Not attrs. | |
machty [8:45 PM] | |
in that case i'd imagine `|c| c.wat` would access `@wat="..."` | |
locks [8:45 PM] | |
:joy: | |
machty [8:45 PM] | |
oh boy | |
locks [8:45 PM] | |
this is good @machty, trust us <3 | |
mmun [8:45 PM] | |
No | |
locks [8:45 PM] | |
they're good components (edited) | |
mmun [8:45 PM] | |
Dont trust us. | |
machty [8:45 PM] | |
i really don't trust yall | |
mmun [8:46 PM] | |
We need to convince people on merit | |
machty [8:46 PM] | |
I really don't believe in the angle bracket push. i believe it to be unbelievably low priority | |
[8:46] | |
for all the stuff missing in ember | |
locks [8:46 PM] | |
2 years in the making isn't low enough priority for you? :P | |
machty [8:46 PM] | |
it's been this hovering ghost of compat issues whenever improvements to the view layer come up | |
12 replies Last reply today at 6:20 AM View thread | |
locks [8:47 PM] | |
I'm interested in having that (other) conversation @machty | |
machty [8:51 PM] | |
@locks which one (sorry might gotten confused by the slack thread thing) | |
locks [8:52 PM] | |
missing stuff in Ember | |
[8:52] | |
I DMed you | |
[8:53] | |
y'all have threads!? | |
machty [8:55 PM] | |
check out my sick new threads (edited) | |
locks [8:55 PM] | |
all I have is fibers | |
machty [9:12 PM] | |
https://github.com/ember-animation/liquid-fire/blob/master/addon/templates/components/liquid-bind.hbs | |
[9:13] | |
there's a lot of examples like these | |
[9:13] | |
i feel like this kind of stuff should be within scope of what i'm/we're proposing | |
[9:13] | |
it's a good case for why `{{component}}` shouldn't be the only way to render these things | |
mmun [11:11 PM] | |
~ | |
runspired [11:22 PM] | |
@mmun: c? | |
mmun [11:28 PM] | |
c | |
runspired [11:34 PM] | |
@mmun: thought maybe you were confused by mentions you don't see | |
[11:34] | |
I replied on that thread above :P | |
alkamin [11:41 PM] | |
joined #topic-forms | |
----- Today January 19th, 2017 ----- | |
locks [6:27 AM] | |
@ryanto @samselikoff I now understand why you were talking about self-contained components ;P | |
[6:27] | |
that countries CP though | |
machty [6:58 AM] | |
@mmun i'm starting to agree that `{{component attrBlock}}` + `|c|` == component instance is wack | |
[6:58] | |
it might be the best option in the end | |
[6:58] | |
but it is weird | |
machty [9:27 AM] | |
OK, here's a rough draft of an RFC of all the bozo stuff we've been talking about | |
[9:27] | |
https://gist.github.com/machty/04aee681d6a0b6fb4484d8c1f8d06d82 | |
[9:27] | |
even though i feel it raised compelling points, it still feels gross? | |
locks [9:34 AM] | |
straps in | |
locks [9:48 AM] | |
> { ... } denotes regions of JavaScript, whereas <...> denotes regions of JSX | |
so this is the crux of the thing (edited) | |
[9:49] | |
```<x-foo | |
header=(|d| | |
<my-header | |
subheader=(|h| | |
<h1>{{d.foo}}, {{h.foo}}, and {{outerFoo}}</h1> | |
) | |
> | |
) | |
> | |
``` | |
is also :+1: @machty ? (edited) | |
machty [9:50 AM] | |
does glimmer make you put `/>` at the end? | |
locks [9:50 AM] | |
I'm curious about 2. unwrapped dom fragments must be supported, is this for parity with blocks? | |
machty [9:51 AM] | |
yeah | |
locks [9:51 AM] | |
oh… I'm not sure angle bracket components have an inline form (edited) | |
machty [9:52 AM] | |
hmm | |
[9:52] | |
`/>` is nicer than just `>` out in the open | |
jrowlingson [9:52 AM] | |
joined #topic-forms | |
locks [9:53 AM] | |
general caveat about angle bracket syntax not existing atm | |
locks [9:53 AM] | |
last time I looked you would have to always do `<my-comp></my-comp>` | |
[9:54] | |
let's shelf it, I don't want to derail | |
machty [9:54 AM] | |
yeah no worries | |
locks [9:56 AM] | |
```{{let header=(|d| I am fragment, hear me {{d.action}})}} | |
{{x-foo header=header}} | |
``` | |
is tight | |
machty [9:56 AM] | |
i think it might be nice to specify the order of importance of various features: | |
1. we shouldn't build out yield; positional params will fragment the ecosystem and (component) works well | |
2. we should continue the pattern of passing in templates/components as attrs, rather than blocks living in their own closed off inaccessible namespace | |
3. (less important but hopeful) a Glimmer syntax that was recursively nestable like JSX would be the most universal solution to this | |
cowboyd [9:58 AM] | |
Thanks @machty for making sure this conversation never stalls out. And for writing two rfcs in like 4 days. | |
locks [9:59 AM] | |
> when passed a template block, render it as a fragment (i.e. tagName: "") | |
this raises some questions wrt event handling and such | |
[9:59] | |
hm | |
[10:01] | |
I don't think enhancing `yield` is a good idea, same situation with `let`/`with` imo. with the slight nuance that I still think `yield` is a useful construct | |
samselikoff [10:03 AM] | |
> that countries CP though | |
@locks where'd you see this, the component args video? | |
locks [10:03 AM] | |
yy | |
[10:04] | |
there was, curiously, a discussion on the pattern of CPs with no dependent keys at #general (edited) | |
[10:07] | |
@machty this rfc would deprecate `{{yield}}`, c/d | |
machty [10:08 AM] | |
no.... probably not | |
[10:08] | |
blurg i dunno, it's weird | |
[10:08] | |
it's like ruby | |
[10:08] | |
what do you do when you want to pass multiple blocks to ruby? | |
[10:09] | |
you can't use the do/end syntax at the end of the method anymore | |
locks [10:09 AM] | |
you cry in a corner because functions aren't first-class | |
machty [10:09 AM] | |
you gotta start passing in options that point to lambdas/procs (possibly constructed w do end) | |
locks [10:09 AM] | |
right | |
machty [10:09 AM] | |
if you're writing a single purpose component then yield's fine | |
locks [10:10 AM] | |
but I still think `yield` is useful | |
[10:10] | |
it's more limited because it's conceptually simpler | |
machty [10:10 AM] | |
(prior art: JSX's this.children pattern vs passing in named props that point to separate compoennts) | |
cowboyd [10:11 AM] | |
I still feel trouble convincing the inner sanctum of my soul of ‘component-centric’ render, even though my rational mind is very close. Let me see if I can’t try and write some of it down. (edited) | |
locks [10:11 AM] | |
this makes sense, and goes with glimmer making component a primitive | |
locks [10:23 AM] | |
@machty seems `<my-component />` is on the table afterall | |
machty [10:30 AM] | |
cool | |
[10:31] | |
well i figure i'll let people comment on this rfc draft today and work out some kinks before posting it | |
[10:31] | |
@locks what's your general feeling? i know this stuff kinda makes you queasy but does it seem over-engineered or anything like that? | |
locks [10:33 AM] | |
I think this is hard to teach and a bit of a slippery slope, but then again people already do all sorts of hacks with private apis and stuff | |
[10:33] | |
but I think it's a good approach | |
machty [10:34 AM] | |
hmm i'm trying to imagine what grandiose feature follows in the same path as this enhancement | |
rlivsey [10:40 AM] | |
joined #topic-forms | |
machty [10:44 AM] | |
`hasBlock` is weird | |
[10:45] | |
the fact that blocks live in their own entire world and need special built-ins to query them is just weird | |
[10:45] | |
i'm sure there's some justification for them | |
[10:45] | |
but i think it could also be explained as an accident of history | |
[10:45] | |
where block helpers were a thing before components | |
[10:45] | |
there was no concept of attrs, no conventions around components | |
machty [11:02 AM] | |
machty's rule of ember composability: if you can't access it in both JS/Handlebars, it's a bad primitive for composition (edited) | |
locks [11:05 AM] | |
oh god, you just made me realize people will programmatically render passed in components | |
machty [11:05 AM] | |
lol i don't think that's possible | |
[11:05] | |
but you should be able to write computed properties dependent on whether there's a block | |
[11:06] | |
blurg i'm sure any one on the core team that was involved in this decision could out argue me but they're still be wrong | |
[11:06] | |
ok i need to actually do work today | |
[11:06] | |
bbl | |
locks [11:06 AM] | |
I think that was simply an oversight | |
[11:07] | |
my webs are dial-speed atm | |
[11:08] | |
nvm, I was thinking of something else | |
[11:08] | |
https://github.com/emberjs/ember.js/issues/11741#issuecomment-121248949 | |
machty [11:13 AM] | |
@locks excellent link | |
machty [11:23 AM] | |
https://github.com/emberjs/rfcs/pull/102 | |
[11:24] | |
it's my hope that my RFC would render 102 moot | |
[11:26] | |
yeah, this stupid channel as addicting af | |
knownasilya [11:29 AM] | |
lol | |
locks [11:29 AM] | |
> It does simply seem odd that you can't use hasBlock as a computed property. | |
[11:30] | |
why can't it be jsut a property :x | |
knownasilya [11:30 AM] | |
yeah.. | |
[11:31] | |
someone should write a bot for slack that saves history periodically for a channel.. | |
[11:31] | |
to a gist like machty is doing | |
locks [11:37 AM] | |
it's against the TOS | |
knownasilya [12:07 PM] | |
ah.. | |
[12:07] | |
lame, but i do like the latest slack features. video and threads.. | |
[12:07] | |
guess we'll live with it :slightly_smiling_face: | |
locks [9:25 PM] | |
@machty https://gist.github.com/carols10cents/b6d03a6da9f2ea950571f59fb19cc56e I think you'll like this | |
machty [10:00 PM] | |
i like those literals in hbs | |
[10:00] | |
`['travis-ci', 'appveyor']` | |
[10:00] | |
should be a thing | |
[10:01] | |
commas are interchangeable with spaces in clj (edited) | |
[10:01] | |
you can use em for clarity, or not | |
locks [10:01 PM] | |
yy | |
machty [10:01 PM] | |
i think i'm gonna submit my rfc | |
locks [10:02 PM] | |
I'd rather not have the commas in hbs tbh | |
machty [10:02 PM] | |
`['travis-ci' 'appveyor']` | |
locks [10:02 PM] | |
nor the array literal ;P | |
machty [10:02 PM] | |
lol why | |
[10:02] | |
you must hate n00bs | |
locks [10:03 PM] | |
with my gguttss | |
[10:03] | |
na, it's just, tricky | |
[10:03] | |
the more JS it looks, the more JS people want to put in | |
machty [10:04 PM] | |
seems fine to let in all the declarative side-effect free things? | |
[10:04] | |
@cowboyd was typing. should i hold off on the rfc til you tell me your component thoughts? | |
cowboyd [10:05 PM] | |
Nah, I need to write them down | |
[10:05] | |
I was actually typing that i never knew that `,` was interchangeable in clj | |
locks [10:05 PM] | |
what I think I want to say: the more different hbs looks, the easier the context switch will be | |
cowboyd [10:05 PM] | |
I guess my brain just erased it | |
locks [10:05 PM] | |
it's like spaces and tabs in ruby | |
[10:05] | |
there's no right answer, but the wrong one is to use tabs | |
cowboyd [10:05 PM] | |
But I can leave that feeback on the rfc, or discuss it in here | |
locks [10:06 PM] | |
I'm about to say something stupid @machty | |
[10:06] | |
I'd rather `{a=3}` be the hash shorthand than `(a=3)`, as well as the lambda syntax (edited) | |
machty [10:07 PM] | |
doesn't sound stupid to me | |
[10:07] | |
haven't really thought too hard about it | |
locks [10:07 PM] | |
I know you don't want to fall into bikeshed pits | |
[10:08] | |
but my goal isn't to argue for arguing | |
[10:08] | |
I'm thinking of clojure here, once again | |
[10:08] | |
and how hickey approached introducing syntax to the language to make it, imo, easier to parse | |
[10:09] | |
like, the parens fall away even more, because now you have some sort of delineation | |
[10:09] | |
"`[]`? ok, those are the function args" | |
cowboyd [10:10 PM] | |
I wonder how vector literals are implemented in clj | |
locks [10:12 PM] | |
I just opened the cljs webpage and regretted it xD | |
[10:12] | |
lovely language, dreadful environment | |
cowboyd [10:13 PM] | |
```user> (macroexpand []) | |
[] | |
user> (type []) | |
clojure.lang.PersistentVector | |
``` | |
[10:13] | |
https://embercommunity.slack.com/archives/topic-forms/p1484881977002508 | |
locks | |
lovely language, dreadful environment | |
Posted in #topic-formsYesterday at 10:12 PM | |
[10:13] | |
whyzat? | |
locks [10:14 PM] | |
it feels completely opaque to me, I want to do some simple thing and have to learn about 10 things | |
[10:15] | |
but they don't even say that there even are 10 things to learn about | |
machty [10:16 PM] | |
i semi-agree | |
[10:16] | |
i definitely agree when it comes to om effing next | |
locks [10:16 PM] | |
haha | |
[10:17] | |
https://clojurescript.org/guides/faq-js#are-there-good-editors-for-clojurescript | |
[10:17] | |
https://clojurescript.org/guides/faq-js#are-there-build-tools-for-clojurescript | |
[10:17] | |
watness | |
[10:17] | |
(Light Table :heart: ) | |
cowboyd [10:17 PM] | |
@locks maven repositories are a fundamental aspect of computer science | |
[10:17] | |
that every programmer needs to learn eventually. | |
locks [10:17 PM] | |
I feel like I'm being trolled | |
[10:17] | |
by you and by maven | |
[10:17] | |
;P | |
cowboyd [10:18 PM] | |
seeing as they underpin all of functional programming | |
locks [10:18 PM] | |
(broccoli has this problem) | |
[10:20] | |
@machty I really wanted to do om | |
[10:20] | |
and especially om.next | |
[10:20] | |
but the incidental complexity killed me | |
machty [10:29 PM] | |
incidental complexity? in clj? no such thing | |
[10:29] | |
trololol | |
[10:29] | |
the hubris attached to that lib is kind of unbearable | |
[10:30] | |
backwards incompatible new version | |
[10:30] | |
advertised as "the way UIs will be built in the future" | |
locks [10:30 PM] | |
sorry, I meant the decomplected complexity | |
machty [10:30 PM] | |
yeah | |
locks [10:30 PM] | |
I do like david nolen | |
[10:30] | |
like, a lot | |
machty [10:30 PM] | |
i'm just salty cuz he made me feel dumb | |
locks [10:30 PM] | |
aw | |
machty [10:35 PM] | |
i want ember to decompose like clojure and i want someone experienced in ember to build frameworks in clojure | |
locks [10:39 PM] | |
thankfully we have you :heart: | |
machty [10:40 PM] | |
we'll see | |
[10:40] | |
might run off once the feedback comes in :slightly_smiling_face: | |
locks [10:44 PM] | |
https://github.com/priyatam/mala did `lein dev`, it's been installing for 1min | |
[10:45] | |
oh jesus | |
[10:46] | |
there's no CSS, it's "garden" | |
[10:46] | |
there a whole dsl for typography | |
runspired [11:12 PM] | |
where is this plato | |
machty [11:13 PM] | |
hahah | |
[11:13] | |
>`{{yield}}` is not the same thing as `{{yield to=(|| {{yield}})}}` | |
[11:13] | |
oh boy | |
[11:13] | |
shouldn't have opened pandora's box here | |
[11:13] | |
i violated moron-moron confidentiality | |
runspired [11:14 PM] | |
oh god you’ve gone too far I cant trust you gtfo | |
machty [11:14 PM] | |
haha | |
[11:14] | |
agree | |
[11:14] | |
vamoose | |
runspired [11:14 PM] | |
I was reading up on some of the proposals in here earlier | |
[11:14] | |
so many good juices flowing | |
----- Today January 20th, 2017 ----- | |
mmun [12:15 AM] | |
actually, `{{yield}}` should be the same thing as `{{yield to=(|| {{yield}})}}` | |
[12:15] | |
blocks should be TCP | |
[12:15] | |
order is restored | |
[12:15] | |
`{{yield to=(|| {{yield}})}}` is a strawman though | |
machty [12:15 AM] | |
define should | |
[12:15] | |
they are? | |
[12:15] | |
or they should be changed to be | |
mmun [12:17 AM] | |
If you define a component | |
```{{!-- components/calendar-wrapper.hbs --}} | |
{{power-calendar dayBlock=(|d| {{yield d}})}} | |
``` | |
and invoke it as | |
```{{#calendar-wrapper as |d|}} {{d.number}} {{/calendar-wrapper}} | |
``` | |
I would expect this be the same as a direct call to | |
```{{power-calendar dayBlock=(|d| {{d.number}})}} | |
``` | |
[12:18] | |
This is precisely the guarantee you get if block lambdas satisfy TCP (edited) | |
[12:20] | |
so, if we assume we the blocks are TCP, it also forces that in a component’s layout `{{invoke (|| {{yield}})}}` is the same as `{{yield}}` (edited) | |
[12:21] | |
{{invoke}} here is just a strawman since i don’t want to get overly attached to {{yield to=block}} (edited) | |
machty [12:21 AM] | |
procs break TCP right? | |
[12:21] | |
gah | |
mmun [12:22 AM] | |
well i wouldn’t phrase it like that | |
machty [12:22 AM] | |
i know | |
mmun [12:22 AM] | |
if your procs are TCP then you can do non-local jumps if you’re not careful (edited) | |
[12:22] | |
if they’re not TCP then you can’t have problems | |
[12:24] | |
my comments above are just listing out properties that I think a reasonable implementation of blocks should have (edited) | |
[12:24] | |
tl;dr i think they should satisfy TCP so you can do the fancy block-forwarding. | |
[12:25] | |
haha... | |
[12:25] | |
and you can make a `(yield)` subexpression which is a shorthand for `(|a b c ...| {{yield a b c ...}})}}`. and obviously for `(yield to='inverse')` as well (edited) | |
[12:25] | |
I remember edward proposing that now | |
[12:27] | |
damn i wish i still had that talk slot for the ember sf meetup | |
[12:29] | |
{{#slot ‘talk’}} | |
machty [12:32 AM] | |
oh interesting | |
[12:33] | |
`(yield)` makes perfect sense | |
[12:33] | |
blurg | |
[12:33] | |
am i right about the component/yield divide? | |
[12:33] | |
is it as big a deal as i'm making it? | |
[12:33] | |
i feel like everyone's already dead set on yield (edited) | |
machty [12:40 AM] | |
alright i'm gonna submit this thing | |
mmun [12:47 AM] | |
https://twitter.com/kelseyhightower/status/774076482637312001 :stuck_out_tongue: | |
Kelsey Hightower @kelseyhightower | |
The best technical discussions focus on trade offs under a given set of constraints; not better or worse comparisons. | |
TwitterSept 8th, 2016 at 10:46 PM | |
machty [12:48 AM] | |
https://github.com/emberjs/rfcs/pull/203 | |
[12:48] | |
here we go | |
[12:48] | |
god this is gonna fail so hard when people see the nested syntax | |
[12:48] | |
alright bedtime | |
[12:49] | |
is sleep TCP? | |
mmun [12:55 AM] | |
:grimacing: | |
sclaxton [1:22 AM] | |
joined #topic-forms | |
sclaxton [1:57 AM] | |
Wow. Shit is crazy | |
slackbot Custom Response [1:57 AM] | |
:explicitwarning: We'd love for this to remain an awesome place for all Emberers. Helps us out by editing that message. :point_up: https://github.com/cromwellryan/embercommunity-slack-guidelines/blob/master/CodeOfConduct.md | |
sclaxton [1:59 AM] | |
personally I feel like `{{component}}` is more of a problem than `{{yield}}` | |
[2:00] | |
It's all about that statically analyzable syntax | |
[2:00] | |
And referential transparency | |
mmun [2:04 AM] | |
hmm, can you elaborate? | |
sclaxton [2:07 AM] | |
`{{component}}` enables more layers of referential indirection by letting you dynamically generate component names to be invoked | |
[2:08] | |
Like it's totally possible to invoke a bunch of components in a project but their invocation site isn't discoverable by searching for the name of the component | |
[2:08] | |
That's :sob: | |
mmun [2:10 AM] | |
hmm, can you give a concrete example? | |
[2:10] | |
dynamic component invocations isn’t really pattern matching with me | |
[2:11] | |
you could imagine a sub-expression form of component invocation that evaluates to a factory (edited) | |
[2:11] | |
`(foo-bar blah="blah")` instead of `(component 'foo-bar' blah="blah")` (edited) | |
sclaxton [2:12 AM] | |
Say I have a bunch of types that the server sends me `red`, `blue`, `green` as string data | |
[2:13] | |
Then I define components `red-car`, `blue-car`, `green-car` | |
[2:15] | |
And invoke them dynamically as `{{component (concat colorType "-car")}}` | |
mmun [2:15 AM] | |
sure | |
[2:15] | |
sounds like a dr. seuss novel | |
sclaxton [2:15 AM] | |
In some ways it's a powerful patrern | |
[2:15] | |
But also terrible imo | |
mmun [2:16 AM] | |
I understand this much of what your wrote. | |
[2:16] | |
I don't understand how it relates to alex's RFC | |
sclaxton [2:16 AM] | |
Just saying things I don't like about `{{component}}` | |
[2:16] | |
Haha | |
[2:18] | |
Since his rfc is deductively `{{component}}` > `{{yield}}` | |
[2:18] | |
*reductively | |
[2:18] | |
Meaning I'm doing the reducting not him heh | |
mmun [2:18 AM] | |
I have to read it carefully still. But going into it I have the same initial feeling as you. (edited) | |
sclaxton [2:19 AM] | |
My rfc on slots isn't great either | |
[2:19] | |
Or doesn't really feel like the "right" solution | |
mmun [2:19 AM] | |
I'm really in favor of {{yield to=...}} + block lambdas | |
sclaxton [2:19 AM] | |
Yah | |
mmun [2:20 AM] | |
at least that's how I'm leaning atm | |
sclaxton [2:21 AM] | |
I do think we need something to solve the general problem these both attempt much sooner rather than later | |
mmun [2:21 AM] | |
hmm, I don't feel the pressure myself. | |
[2:21] | |
I've only written one component at work that would have benefited from it | |
[2:22] | |
but I do feel bad for addon authors that are struggling with their own complex components | |
sclaxton [2:22 AM] | |
It's mostly those writing component libraries that would benefit | |
[2:22] | |
Yep | |
[2:22] | |
But that's a pretty huge part of the ember ecosystem | |
[2:23] | |
If we have a strong set of usable and reusable components, we have a strong UI building ecosystem | |
mmun [2:24 AM] | |
ah you work at linkedin | |
[2:24] | |
I'm in SF until next saturday :slightly_smiling_face: | |
sclaxton [2:24 AM] | |
Guilty haha | |
mmun [2:25 AM] | |
you should socialize block lambdas internally (if you support it) (edited) | |
[2:25] | |
I think several people there are really focused on a slot syntax (edited) | |
[2:25] | |
given the messages that chad shared a few minutes ago :stuck_out_tongue: | |
sclaxton [2:26 AM] | |
Tweets or slack? | |
[2:26] | |
But yeah, that makes sense | |
[2:26] | |
I'm certainly one of them | |
mmun [2:26 AM] | |
the ember core slack, private chan | |
[2:26] | |
I would share otherwise but feels backstabby | |
sclaxton [2:26 AM] | |
Gotcha | |
[2:26] | |
No worries | |
mmun [2:27 AM] | |
I'm not opposed to a slot syntax. I think I do prefer block lambdas | |
sclaxton [2:28 AM] | |
So block lambda are an alternative? | |
mmun [2:29 AM] | |
I think slot syntax has more edge cases to design around | |
sclaxton [2:29 AM] | |
Is there somewhere I can read up on that idea? | |
mmun [2:29 AM] | |
Machty's RFC might discuss it | |
sclaxton [2:29 AM] | |
Kk | |
mmun [2:29 AM] | |
are you goin to the ember meetup? | |
sclaxton [2:30 AM] | |
Ember SF? | |
mmun [2:30 AM] | |
ya | |
[2:30] | |
next tues | |
sclaxton [2:31 AM] | |
I should be able to make it | |
mmun [2:31 AM] | |
i will try too! | |
sclaxton [2:33 AM] | |
Dope. Much block invitation syntax discussion will be had by all | |
[2:35] | |
are block lambdas the `(|| {{stuff}})` business? | |
[2:37] | |
how would that receive the block params? | |
mmun [2:47 AM] | |
(|o hi| ...) | |
sclaxton [2:47 AM] | |
but like where are those coming from? | |
1 reply Today at 4:05 AM View thread | |
sclaxton [2:48 AM] | |
where are they yielded from and how I guess | |
[2:48] | |
its anonymous right? | |
[2:49] | |
with named slots you yield to the named block | |
[2:49] | |
I think I’m missing something with how you would invoke a block lambda | |
runspired [3:20 AM] | |
@mmun I didnt realize you were in town | |
[3:20] | |
we should hang :slightly_smiling_face: | |
[3:22] | |
@sclaxton we actually have a path for making component statically analyzable once the modules rfc lands | |
mmun [3:48 AM] | |
let's! | |
[3:49] | |
fwiw the `(|| ...)` syntax is not really acceptable to me because the `...` could very likely contain a `)` (edited) | |
sclaxton [4:02 AM] | |
@runspired yeah I’ve heard talk of that as well | |
[4:03] | |
I guess that’s fine | |
[4:03] | |
I feel like the real argument here is what’s the atomic template primitive we want to expose to users, blocks or components (edited) | |
[4:04] | |
With named slots components essentially become a keyed collection of blocks arranged in some way | |
[4:05] | |
so blocks would be the atomic primitive | |
[4:06] | |
what is? | |
[4:07] | |
right now block don’t really seem like a front-and-center primitive because they’re essentially treated as an implementation detail of components (edited) | |
[4:08] | |
block lambdas would also have the effect of making blocks the primary template atom (edited) | |
locks [4:14 AM] | |
has anyone read the slot syntax thing of web components? | |
sclaxton [4:14 AM] | |
parts | |
[4:15] | |
I feel like it should be pretty orthogonal to ember “slots" no? | |
[4:15] | |
which is why we maybe should stop calling them slots? | |
locks [4:16 AM] | |
http://stackoverflow.com/questions/38540025/web-components-why-content-was-replaced-with-slot | |
stackoverflow.com | |
Web Components - why was replaced with | |
Version 1.0 of Shadow DOM will completely replace the <content> tag with <slot>. There are examples on the web I cannot find a relevant discussion which justifies this change.What was... | |
[4:16] | |
aren't they the same thing? | |
sclaxton [4:17 AM] | |
cause like shadow dom isn’t really a model that’s relatable to Ember? (edited) | |
[4:17] | |
unless I havne’t thought hard enough about it | |
[4:17] | |
which is almost certainly true | |
locks [4:18 AM] | |
well, sure | |
[4:18] | |
but ignore the shadow dom bit | |
[4:18] | |
that's only relevant for CSS right? | |
sclaxton [4:19 AM] | |
I honestly also need to readup on shadow dom | |
locks [4:19 AM] | |
I wouldn't :D | |
sclaxton [4:19 AM] | |
I thought it was basically just dom that doesn’t actually live in the dom tree | |
[4:19] | |
it’s not exposed | |
[4:19] | |
it’s in the…shadows | |
locks [4:20 AM] | |
the web component crew really :poop3d: it imo | |
[4:20] | |
custom elements v1 are nice I guess | |
sclaxton [4:20 AM] | |
which is why we stopped tracking our components with web components right? | |
locks [4:20 AM] | |
still getting used to the massive api change | |
[4:21] | |
kinda, yeah | |
[4:21] | |
anyway, I mention slots because of that too | |
[4:21] | |
he WC slots don't look that good | |
sclaxton [4:21 AM] | |
I mean it’d be cool if we could make ember slots web components slots + handlebars block params or something | |
[4:22] | |
cause web standards | |
[4:22] | |
but not cool cause I like Ember’s mental model better | |
locks [4:22 AM] | |
"cause web standards" isn't valid here imo | |
sclaxton [4:22 AM] | |
I think Ember slots would literally just be extending `yield` | |
locks [4:23 AM] | |
they refused to shift course | |
sclaxton [4:23 AM] | |
to yield to a certain “sub-block” of components | |
[4:23] | |
so it’s like web components only in the sense that it’s putting content somewhere heh | |
[4:24] | |
the machinery would be the exact same as now | |
locks [4:44 AM] | |
https://hayato.io/2016/shadowdomv1/#insertion-points-v0-vs-slots-v1 I can't even at this hour of the day | |
sclaxton [4:50 AM] | |
"Shadow piercing combinators" | |
[4:50] | |
chills | |
machty [6:46 AM] | |
> I'm really in favor of {{yield to=...}} + block lambdas | |
[6:47] | |
this is likely to be the most common response | |
[6:50] | |
but you can't just say you prefer it without addressing the semantic divide and fragmentation that'll occur by allowing both | |
[6:50] | |
both component and yield | |
machty [7:03 AM] | |
just added this to rfc PR | |
[7:03] | |
i hope it's not too jerkish | |
[7:03] | |
```By submitting feedback to this (likely to be controversial) RFC, you are implicitly agreeing to the statement below: | |
I, Ember enthusiast, have, to the best of my efforts, fully absorbed the nuances of the {{yield}} vs {{component}} APIs, and I understand machty's concerns about the fragmentation that would occur if we continued to build out the {{yield}} API in such a way that "named yields" were not effortlessly interchangeable with the attr=(component ...) pattern. | |
``` | |
locks [7:04 AM] | |
:joy: | |
[7:04] | |
I :heart: you @machty | |
machty [7:12 AM] | |
uploaded this image: Pasted image at 2017-01-20, 7:12 AM | |
Add Comment | |
locks [7:16 AM] | |
don't be afraid @miguelcobain | |
miguelcobain [7:17 AM] | |
I always thought that component blocks were very similar to `{{#if`s. Allow me to explain: | |
- we can use the simple form | |
```{{#if boolean}} | |
{{!-- main block --}} | |
{{/if}} | |
``` | |
just like components | |
```{{#my-component}} | |
{{!-- main block --}} | |
{{/my-component}} | |
``` | |
- however, we can also use the inverse blocks | |
```{{#if boolean}} | |
{{!-- main block --}} | |
{{else}} | |
{{!-- inverse block --}} | |
{{/if}} | |
``` | |
A component also has an inverse block. But why not expanding this syntax for a proper blocks support? | |
```{{#my-component}} | |
{{!-- main block --}} | |
{{block "header"}} | |
{{!-- header block --}} | |
{{/my-component}} | |
``` | |
We should be able to pass in an arbitrary number of blocks and block params: | |
```{{#my-component}} | |
{{!-- main block --}} | |
{{block "header"}} | |
{{!-- header block --}} | |
{{block "footer" as |year|}} | |
{{!-- header block --}} | |
Copyright {{year}}. | |
{{/my-component}} | |
``` | |
In the component's layout, we would use the current api for yielding to inverse blocks, but with named blocks: | |
```{{yield to="header"}} | |
{{yield}} | |
{{yield to="footer" currentYear}} {{!-- this is a bit strange --}} | |
``` | |
For recreational purposes, we should be able to recreate an `{{#if` equivalent using just component constructs: | |
```{{#if-component boolean}} | |
{{!-- main block --}} | |
{{block "else"}} | |
{{!-- else block --}} | |
{{/if-component}} | |
``` | |
and the component's template | |
```{{#if boolean}} | |
{{yield}} | |
{{else}} | |
{{yield to="else"}} | |
{{/if}} | |
``` | |
this is just to illustrate the similarities with `{{#if`. (edited) | |
[7:18] | |
The only thing still missing is to solve the problem with components without main blocks. | |
locks [7:20 AM] | |
not sure I agree | |
[7:21] | |
the conditional behaviour of components is handlebars helpers baggage | |
[7:21] | |
and we don't have a `case` in handlebars, which seems like the more apt correlation to slots | |
miguelcobain [7:23 AM] | |
@machty's RFC is certainly more flexible. | |
> a) whenever the components need to be used in multiple places and b) whenever the template block grows so large that it'd be easier to understand as a separate file. | |
(edited) | |
locks [7:23 AM] | |
this reminds me a point sandi metz made in a talk about `if` in smalltalk | |
[7:26] | |
https://www.youtube.com/watch?v=9lv2lBq6x4A | |
YouTube Confreaks | |
BathRuby 2015 - Nothing is Something | |
machty [7:27 AM] | |
is there a more specific time? | |
locks [7:28 AM] | |
the preamble kinda sets up the context | |
[7:28] | |
but ~3min | |
[7:28] | |
3min exactly, actually | |
machty [7:31 AM] | |
i hope to attain 3% of her command of audience by the time emberconf rolls around | |
locks [7:31 AM] | |
sandi and katrina owen are like, up there | |
machty [7:32 AM] | |
i read the sandi metz red ruby book | |
[7:32] | |
still definitely don't unit test | |
locks [7:32 AM] | |
haha | |
machty [7:32 AM] | |
i mean, not to her degree | |
[7:33] | |
having to test A and B in isolation, AND ensure the mocks follow along with changes to either's API is harrowing af | |
[7:33] | |
i wish i'd seen this talk 8 years ago | |
locks [7:35 AM] | |
I'm so bummed for not being able to go to emberconf | |
machty [7:37 AM] | |
i'd love to see sandi and rich hickey have a convo | |
[7:37] | |
so much of FP is case-matching against known types _by intention_ | |
locks [7:45 AM] | |
```~/s/e/ember.js git:(master) yarn update glimmer-engine | |
yarn update v0.17.10 | |
error Did you mean `yarn upgrade`? | |
info Visit https://yarnpkg.com/en/docs/cli/upgrade for documentation about this command. | |
``` | |
[7:45] | |
why didn't this just work | |
machty [7:46 AM] | |
brew upgrade is different than update | |
[7:46] | |
if they just made it work then they wouldn't be able to add that in the future | |
locks [7:49 AM] | |
I wonder how much justification there is for the api decisions | |
[7:49] | |
like, npm update -> yarn upgrade (kinda) | |
machty [7:51 AM] | |
i can never remember | |
miguelcobain [7:52 AM] | |
npm install --save -> yarn add | |
locks [7:52 AM] | |
any thoughts on https://embercommunity.slack.com/archives/topic-forms/p1484914661002763 ? (edited) | |
[7:53] | |
I mean, it kinda makes sense to have different terminology for different semantics | |
machty [7:53 AM] | |
i'm not sure how it ties in or what it's recommending | |
[7:53] | |
it doesn't address the component/yield divide | |
[7:54] | |
(minor correction: `{{yield to="footer" currentYear}}` needs to be `{{yield currentYear to="footer"}}`) (edited) | |
miguelcobain [8:01 AM] | |
@machty component/yield divide? | |
machty [8:04 AM] | |
@miguelcobain oh, i was assuming your if/component comparison was in regards to the rfc https://github.com/emberjs/rfcs/pull/203 | |
miguelcobain [8:06 AM] | |
I was basically suggesting a blocks syntax. | |
[8:06] | |
And trying to understand why something like that wouldn't work. | |
[8:06] | |
(You gave this topic a lot more thought than i did) | |
machty [8:07 AM] | |
word | |
[8:07] | |
wellll this is my dissertation: https://github.com/machty/rfcs/blob/nested-handlebars/text/0000-nested-handlebars-syntax.md#why-not-yield | |
miguelcobain [8:35 AM] | |
Somehow, things made more sense the second time I read it. Thanks. | |
[8:37] | |
@machty does your RFC include `yield` deprecation? Because with that API, `{{yield` wouldn't be needed anymore. (edited) | |
machty [8:37 AM] | |
I don't know, probably not | |
[8:37] | |
that'd be a bit too bold | |
[8:37] | |
i'll wait for feedback first | |
locks [8:57 AM] | |
just to be clear, if `yield` would get deprecated in function of this rfc, it would be an additional deprecation rfc | |
machty [8:59 AM] | |
yeah | |
[8:59] | |
my hope is that people take seriously the yield/component divide, adapt to the arguments made, and refine the role that `yield` should take | |
[9:00] | |
i'm not privy to lots of internal glimmer convos so i def can't predict the response | |
locks [9:00 AM] | |
I'd be interested to see someone make a generators correlation | |
machty [9:01 AM] | |
how so? (edited) | |
[9:02] | |
generator functions or ember-cli generators? | |
locks [9:02 AM] | |
generator functions | |
cowboyd [9:07 AM] | |
I do take seriously the yield component / divide, but doesn’t it also only make sense if `positionalParams` api is deprecated? Because isn’t that cat out of the bag already? | |
[9:09] | |
Do I understand correctly that if a component uses `positionalParams`, then it _cannot_ be rendered programmatically? | |
locks [9:09 AM] | |
we need splat operator and the router service (in master behind a feature flag, woop woop) to kill positional params (edited) | |
cowboyd [9:11 AM] | |
but is the plan to do that? | |
[9:11] | |
irrespective of @machty’s rfc? (edited) | |
locks [9:11 AM] | |
I don't think there's an actual plan | |
[9:11] | |
but positional params are costly | |
[9:11] | |
and some people would like to axe them | |
[9:11] | |
right @serabe | |
cowboyd [9:13 AM] | |
I definitely feel like a choice must be made between eliminating positional params on the one hand, or extending programmatic rendering to account for them. | |
[9:13] | |
The situation where a subset of components are magically 2nd class because they use an api is an unfortunate one. | |
locks [9:14 AM] | |
I think the concerns about the splat operator are in the hbs repo | |
[9:14] | |
positional params are 2nd class ;X | |
machty [9:16 AM] | |
how would you extend the programmatic rendering? (edited) | |
cowboyd [9:17 AM] | |
I don’t know, but I’m curious to explore it in order to more fully understand the choice, because if I understand it, then it it is a mutually exclusive one. | |
rwjblue [9:17 AM] | |
@machty can ask questions RE RFC#203 here? | |
[9:18] | |
The examples leave me wondering a number of things | |
cowboyd [9:19 AM] | |
seems like you would have to be able to bind p-params from a template. Right now it’s a JS only thing (edited) | |
[9:20] | |
(and is therefore subject to @machty’s rule of weak sauce) | |
machty [9:24 AM] | |
@rwjblue of course | |
rwjblue [9:24 AM] | |
I have a list, and don't want to derail convo | |
cowboyd [9:24 AM] | |
derailing the convo is the official topic of this channel. | |
rwjblue [9:24 AM] | |
LOL | |
[9:24] | |
OK | |
cowboyd [9:24 AM] | |
In a very positive way | |
rwjblue [9:25 AM] | |
```// classic curly style: | |
{{media-player | |
tracklist=(|data| | |
{{#each data.tracks as |t|}} | |
<div class="track">{{ track.name }}</div> | |
{{/each}} | |
) | |
}} | |
``` | |
* What is `data`? How is it passed in? | |
* What does `media-player`'s `layout` look like? (edited) | |
[9:25] | |
Further down you suggest that it would invoke `tracklist` via `{{component` right? | |
[9:26] | |
I suspect it might be something like: | |
```{{component tracklist}} | |
``` | |
cowboyd [9:27 AM] | |
iirc `{{component tracklist tracks=model.tracks}}` right? | |
rwjblue [9:27 AM] | |
I am not fond of the idea that the hash arguments are basically turned into a POJO that is the first block param. | |
[9:28] | |
`{{component` already supports positional arguments, why would we not use them? | |
[9:29] | |
Also, the RFC talks alot about "we are not using yield" and "why not yield", but I don't really see the explanation that I can get behind | |
[9:29] | |
I totally dig invoking via `{{component` helper (or a new helper for `{{block` or whatever) | |
[9:30] | |
however, saying "we are not using `{{yield}}`" seems weird | |
[9:32] | |
because the first thign I wanted to do when reading the snippet I pasted above was: | |
```{{media-player | |
tracklist=(|data| | |
{{#each data.tracks as |t|}} | |
<div class="track">{{yield t}}</div> | |
{{/each}} | |
) | |
}} | |
``` | |
media-player's layout: | |
```{{#component tracklist tracks=whatever as |track|}} | |
<a href={{url-for 'track.details' track}}>track.title</a> | |
{{/component}} | |
``` | |
(edited) | |
[9:32] | |
I don't think its "lets not use yield" so much, as "lets use yield for its intended purpose" | |
machty [9:33 AM] | |
what is `<div class="track">{{yield t}}</div>`? | |
rwjblue [9:33 AM] | |
I made it up | |
[9:33] | |
if you can pass blocks, and those blocks are basically like components, why can't you yield? | |
machty [9:33 AM] | |
how would media-player's layout component render that? (edited) | |
rwjblue [9:34 AM] | |
thats the second snippet (edited) | |
cowboyd [9:34 AM] | |
My natural intuition is to render the head of every expression: | |
```{{#x-foo as |a b c=}} | |
{{a}} {{b} {{c}} | |
{{/x-foo}} | |
``` | |
whose template looks like: | |
```{{yield a b c=d}} | |
``` | |
is really just a synonym for: | |
machty [9:34 AM] | |
that looks like really intensively recursive stuff @mmun and i were half-jokingly discussing last night | |
cowboyd [9:34 AM] | |
```{{x-foo yield=(|a b c=|) {{a}} {{b}} {{c}} }} | |
``` | |
(edited) | |
[9:35] | |
i.e. helper-less render. | |
rwjblue [9:36 AM] | |
anyways, the focus on "why not yield" distracts from the proposal IMO | |
[9:36] | |
I quite like the primitive you are suggesting | |
[9:36] | |
assuming we can do it and not feel like a "bolt on" after the fact thing | |
[9:37] | |
:clap: :clap: for convincing me of one of these "slots" RFC's :slightly_smiling_face: (edited) | |
machty [9:37 AM] | |
@rwjblue if you stick with the pattern it's: | |
```consumer: | |
{{media-player | |
tracklist=(|data| | |
{{#each data.tracks as |t|}} | |
<div class="track">{{component t...CRAP I DUNNO}}</div> | |
{{/each}} | |
) | |
}} | |
media-player layout: | |
{{component | |
tracklist tracks=whatever | |
snippet=(|a| | |
<a href={{url-for 'track.details' a.track}}>{{a.track.title}}</a> | |
) | |
}} | |
``` | |
[9:38] | |
i don't know what to tell you about what roll `{{yield}}` should have | |
[9:38] | |
just that one you start using it, you've severed swappability with `{{component}}` | |
[9:38] | |
and i don't know where to tell you where one API should begin and the other end | |
rwjblue [9:38 AM] | |
to me, it depends on what the point is | |
machty [9:38 AM] | |
just that the one thing that's certain is that we should not extend `{{yield}}` to be more powerful than it is | |
[9:38] | |
also, you kinda snuck in a feature that you can't even do today with yield | |
rwjblue [9:39 AM] | |
if the idea is that `tracklist` is "just like any other component" it should be able to yield (edited) | |
machty [9:39 AM] | |
block templates today can't yield | |
[9:39] | |
but you provided an example in the proposed RFC style where it does | |
rwjblue [9:39 AM] | |
@machty totally agreed, *but* you are essentially saying this is a component (you don't propose `{{block` helper, you use `{{component` helper) | |
[9:40] | |
if it is a component, it should be a component | |
[9:40] | |
otherwise you have super weird rules about what is allowed and what is not in a "component" template | |
[9:40] | |
which (if I read them right) violates "machty's rules of lame sauce" | |
machty [9:41 AM] | |
what are these weird rules? | |
rwjblue [9:42 AM] | |
if I write a component template (actually layout but whatevs) I can use `{{yield` to yield to the provided block | |
[9:42] | |
if I do your proposed thing, I cannot | |
[9:42] | |
even though it is effectively being called a "component" | |
[9:43] | |
or do you mean the rules of lame/weak sauce? (because I thought you made that up?) (edited) | |
machty [9:45 AM] | |
there's nothing in my RFC that prevents what you're trying to do | |
cowboyd [9:45 AM] | |
Hah. The rule I was referring to was what you coined way up in the convo which called any API that was Hbs only was lamesauce. | |
[9:45] | |
A sentiment with which I wholeheartedly agree. | |
machty [9:46 AM] | |
my RFC just points out in no uncertain terms that we already have this problem today (you can pass in chunks of dom via both attr=(component) and yield-able templates to component) and we should standardize on a story/future and please god i hope it's not to put fuel on the fire by extending yield | |
[9:46] | |
https://gist.github.com/machty/68afad4c03109f36d4f4cffaae3c170b#file-gistfile1-txt-L7193 | |
[9:47] | |
i replaced "weak sauce" with "bad primitive for composition" | |
rwjblue [9:47 AM] | |
but weaksauce was better :slightly_smiling_face: | |
[9:47] | |
@machty the thing is, `{{yield` has a purpose today | |
[9:47] | |
unless you are suggesting that we deprecate it completely, it likely will still have a use case | |
machty [9:48 AM] | |
TBD. i don't have an answer yet | |
[9:48] | |
i just wanna get everyone talking about the same thing | |
[9:48] | |
(and i have succeeded :slightly_smiling_face: ) | |
locks [9:48 AM] | |
extending yield to support slots, right (edited) | |
machty [9:48 AM] | |
:troll: | |
[9:49] | |
that was a good one | |
locks [9:49 AM] | |
first rule of slots club is you talk about lambdas | |
rwjblue [9:49 AM] | |
@machty I don't agree with some of the choices you have made here (e.g. I don't think we should use hash args into a single pojo), but overall the general thrust of "lets make it nestable" is good | |
machty [9:50 AM] | |
@rwjblue if you don't like that then you need to counter with an alternative that preserves attr=(component) swappability | |
rwjblue [9:50 AM] | |
ha! I don't *need* to do anything | |
[9:50] | |
I'm just going to sit back and what and see what happens | |
[9:50] | |
remember I am the thought laggard, I just like doing mountains of work | |
[9:51] | |
Also, I have no clue wtf `attr=(component)` swappability means | |
machty [9:51 AM] | |
https://github.com/machty/rfcs/blob/nested-handlebars/text/0000-nested-handlebars-syntax.md#why-not-yield-impedance-mismatch-with-component | |
rwjblue [9:53 AM] | |
yeah, don't get it | |
machty [9:53 AM] | |
you don't like the attrs pojo | |
rwjblue [9:54 AM] | |
well, my issue is mostly with lack of splat | |
[9:54] | |
if we had splat I would have no issue | |
machty [9:54 AM] | |
but that constraint is that layout templates render attr compoents via `{{component attr foo=123}}` | |
[9:54] | |
and that works today if you passed in `attr=(component 'x-lol')` | |
rwjblue [9:55 AM] | |
with hash args being translated automatically to a pojo and passed as block params, you loose the ability to actually create the attrs in JS space | |
machty [9:55 AM] | |
`x-lol` receives foo=123 as an attr along with anything else | |
rwjblue [9:55 AM] | |
which is "weaksauce"? | |
machty [9:55 AM] | |
so if you wanted to replace `attr=(component 'x-lol')` with `attr=(|xyz| <div>inline template from RFC</div>)`, what else could `xyz` possibly be | |
[9:56] | |
without requiring your layout template change the way it renders | |
[9:56] | |
how would splats help here | |
rwjblue [9:56 AM] | |
my issue is with not being able to dynamically change the arguments in JS | |
machty [9:57 AM] | |
that is an orthogonal feature | |
[9:57] | |
(that i too want, and happened to have implemented) | |
rwjblue [9:57 AM] | |
hah! its all orthogonal :stuck_out_tongue: | |
machty [9:57 AM] | |
but whether there's splat or no, the block param can't be anything but a pojo of attrs | |
rwjblue [9:58 AM] | |
yeah, I don't really see why | |
machty [9:58 AM] | |
(destructuring syntax might also help) | |
[9:58] | |
> so if you wanted to replace `attr=(component 'x-lol')` with `attr=(|xyz| <div>inline template from RFC</div>)`, what else could `xyz` possibly be | |
[9:58] | |
@rwjblue this is the question | |
rwjblue [9:58 AM] | |
to change from `attr=(component 'foo')` to `attr=(|xyz| sasdfasdfsd)` you still have to change many things | |
machty [9:58 AM] | |
like? | |
rwjblue [9:58 AM] | |
`foo` template? (edited) | |
[9:59] | |
the place where this invocation is (obviously) (edited) | |
[9:59] | |
now, we could do an awesome thing and have named block params | |
[9:59] | |
but that also seems hard | |
[10:00] | |
(though maybe not, since the block param syntax is more constrained already) | |
[10:00] | |
but I guess then you would have to duplicate / repeat yourself | |
[10:01] | |
`attrs=(|name=name title=title| {{name}})` or whatever | |
[10:01] | |
which kinda sucks (edited) | |
locks [10:01 AM] | |
`attrs=(|(name,title)| {{name}})` | |
[10:02] | |
only half joking, what I mean with ^ is "destructuring" | |
machty [10:02 AM] | |
obviously if you make the refactoring decision to change from passing `attr=(component 'x-bar')` into an inline template, you'll need to copy x-bar's template into the inline template block and change prefix what used to be references to attrs with `theBlockParam.` | |
[10:02] | |
the point is that `media-player` or whatever shouldn't have to change to accommodate that | |
[10:03] | |
it should keep on keepin on rendering components with `{{component myAttr some=value}}` | |
rwjblue [10:03 AM] | |
hmm, I thought you were suggesting that you might want to wrap a component | |
[10:04] | |
`attr=(component 'x-lol')` with `attr=(|xyz| <div class="special">{{component 'x-lol' ...xyx}}</div>)` which is where I went on with wanting splat / spread / whatever (edited) | |
[10:05] | |
it would be nice if ^ refactoring could happen without changing `x-lol` layout at all | |
machty [10:06 AM] | |
that is an excellent use case | |
[10:07] | |
lemme think about that | |
[10:07] | |
i understand the use case you're describing | |
[10:07] | |
you understand mine too, right? | |
rwjblue [10:07 AM] | |
aye | |
machty [10:07 AM] | |
:+1: | |
[10:07] | |
yeah you'd need splat syntax | |
[10:07] | |
for what you're describing | |
rwjblue [10:07 AM] | |
I only _slightly_ dislike the thing I was talking about BTW, 90% +1 on your proposal | |
[10:08] | |
its hard to make it clear that I know I am talking about edge cases | |
machty [10:08 AM] | |
well you don't strictly need splat syntax | |
[10:08] | |
you could explicitly list out all the properties you wanna pass | |
[10:08] | |
but that sucks | |
rwjblue [10:08 AM] | |
which completely couples everythign (edited) | |
machty [10:08 AM] | |
it does and it doesn't | |
rwjblue [10:08 AM] | |
imagine that it was `attr=(component somethingPassedIn)` instead | |
machty [10:09 AM] | |
if `media-player` starts adding new attrs, the components that receive it would need to change in order to start using those attrs | |
rwjblue [10:09 AM] | |
now the "middle" layer must be aware of all the properties | |
machty [10:09 AM] | |
pre-existing attrs that were already being manually forwarded due to lack of splat syntax will continue to propagate the change just fine | |
rwjblue [10:09 AM] | |
confirm | |
machty [10:09 AM] | |
but confirm: now the "middle" layer must be aware of all the properties | |
rwjblue [10:10 AM] | |
I dont really think it is a new problem though | |
[10:10] | |
so likely doesn't make sense to address in this RFC | |
knownasilya [10:11 AM] | |
If the middle layer had a way to access all properties, e.g. `attrs` property, then it would be less of an issue | |
rwjblue [10:11 AM] | |
but can I just say damn you people for making another channel I have to read? | |
locks [10:11 AM] | |
#sorrynotsorry | |
rwjblue [10:11 AM] | |
@knownasilya not really, because even if you know them in JS you can't pass them all in templateland | |
locks [10:11 AM] | |
btw, I can rename the channel | |
[10:11] | |
#dev-dev-ember? :joy: | |
rwjblue [10:11 AM] | |
#dreamland | |
locks [10:11 AM] | |
I know, #weaksauce | |
[10:12] | |
@mmun what were the splat blockers? (edited) | |
knownasilya [10:12 AM] | |
@rwjblue you could if you made them into an array, [{key, value}] | |
[10:12] | |
but you lose the context | |
[10:12] | |
putting all the attrs on equal ground | |
rwjblue [10:13 AM] | |
locks IIRC it was kpdecker? | |
[10:13] | |
but I can't really remember | |
machty [10:13 AM] | |
no, it's blocked by yehuda and Glimmer concerns | |
knownasilya [10:13 AM] | |
so yeah, for anything worthwhile the middleman needs to be updated | |
rwjblue [10:13 AM] | |
@machty nice | |
machty [10:13 AM] | |
kpdecker was +1 | |
rwjblue [10:13 AM] | |
@knownasilya right, which hurts composability | |
[10:13] | |
IMO | |
[10:14] | |
@machty any idea if we can try to shake it loose? | |
machty [10:14 AM] | |
I don't know | |
[10:14] | |
last I heard he had perf concerns | |
[10:14] | |
and perhaps it doesn't model well in the Reference abstraction | |
rwjblue [10:14 AM] | |
interesting | |
machty [10:15 AM] | |
but the composability story is hurting without it | |
[10:15] | |
React has proven this | |
rwjblue [10:15 AM] | |
it sounds like vague "I am unsure what the future is and it makes me uncomfortable to add new syntax until this other stuff I really care about is done".... (edited) | |
[10:16] | |
which is reasonable, but frustrating | |
machty [10:16 AM] | |
yeah | |
[10:16] | |
i think we're nearing that point | |
[10:16] | |
@runspired seems to think so | |
[10:16] | |
the point of comfort to add things | |
rwjblue [10:17 AM] | |
@machty ya | |
[10:17] | |
@machty hurry up and finish this RFC so we can actually do it would ya? (edited) | |
locks [10:18 AM] | |
:thinking_face: | |
[10:18] | |
we could try to overwhelm yehuda while he's vulnerable :troll: | |
machty [10:18 AM] | |
lol what do you think i've been doing https://twitter.com/machty/status/822416787971145728 | |
Alex's Matchneer @machty | |
Here's a controversial Ember RFC for y'all https://github.com/emberjs/rfcs/pull/203 https://pbs.twimg.com/media/C2nPe_qXgAAZWhU.jpg | |
TwitterToday at 7:13 AM (75KB) | |
locks [10:19 AM] | |
so atm | |
[10:19] | |
- let | |
- captured blocks | |
- splat | |
? | |
[10:20] | |
I was talking about ember at yesterday's meetup | |
[10:20] | |
and I explained how ember is the land of "it'll get better soon" | |
samselikoff [10:22 AM] | |
thats so defensive lol. not very compelling.. | |
knownasilya [10:22 AM] | |
haha | |
samselikoff [10:22 AM] | |
not how i would sell it :stuck_out_tongue: | |
knownasilya [10:22 AM] | |
and it does, but then we want more :slightly_smiling_face: | |
samselikoff [10:22 AM] | |
aye | |
locks [10:23 AM] | |
that wasn't how I sold it :P | |
knownasilya [10:24 AM] | |
he said use vue :stuck_out_tongue: | |
locks [10:24 AM] | |
and not quite how I phrased it | |
[10:24] | |
in other words "stability without stagninity" | |
rwjblue [10:24 AM] | |
hah, I have been a Cubs fan my whole life | |
locks [10:24 AM] | |
well, it _has_ been getting better | |
rwjblue [10:24 AM] | |
"theres always next year" is in my blood | |
machty [10:25 AM] | |
lol stagninity | |
locks [10:25 AM] | |
we can has a lot of nice things | |
machty [10:25 AM] | |
strategery | |
knownasilya [10:25 AM] | |
this is the goof-off channel | |
locks [10:26 AM] | |
I was mentioning module unification, javascript import api, `class` support, tree shaking, lazy loaded engines, etc | |
knownasilya [10:26 AM] | |
lazy loaded engines are a thing, just not routeless | |
[10:26] | |
but there are a bunch of caveats lol | |
[10:27] | |
but there is caviar | |
locks [10:27 AM] | |
right | |
[10:27] | |
and you can't share components, and there's still a bunch of overhead, etc | |
[10:28] | |
but it's something that was "we'll get there" and we did | |
[10:28] | |
for almost free for users :D | |
mmun [11:18 AM] | |
what do we do about right parens in content? (edited) | |
[11:18] | |
escape it? | |
machty [11:19 AM] | |
i don't have a good answer | |
[11:20] | |
differing to opinionated people | |
[11:20] | |
might make sense try treat it like do/end in ruby which have expectations of being preceded by newline | |
mmun [11:26 AM] | |
i dont think that works nicely with one-liners (edited) | |
locks [11:28 AM] | |
we can have ( an escaping character | |
[11:28] | |
`((()` if you want a `)` in your content | |
mmun [11:30 AM] | |
@machty do you also feel that a regular block helper invocation should be able to replace the block with a component? | |
rwjblue [11:30 AM] | |
@locks the trolls are strong with this one | |
knownasilya [11:30 AM] | |
:troll: | |
mmun [11:31 AM] | |
{{#my-component}} foo {{/my-component}} | |
{{my-component &default=(component 'foo')}} | |
machty [11:31 AM] | |
only if there are no block params i guess | |
knownasilya [11:32 AM] | |
component blocks still have their place I feel, especially for bigger content that doesn't get duplicated | |
[11:32] | |
easier to refactor and read IMO | |
[11:33] | |
inline-components make sense when using thirdparty code and you need to override a small piece, instead of the whole thing with the default block. | |
[11:34] | |
or your own code that is generalized | |
mmun [11:35 AM] | |
machty: so then if you want to remain compatible {{yield}} has to be able to yield to a component | |
[11:35] | |
_I rest my case your honour_ | |
rwjblue [11:35 AM] | |
:popcorn: | |
machty [11:36 AM] | |
@mmun what happens if it yields positional block params? | |
mmun [11:39 AM] | |
you must use positional params | |
[11:40] | |
you're the one that wants blocks & components to be interchangeable. you tell me! (edited) | |
machty [11:41 AM] | |
there's no good answer | |
locks [11:41 AM] | |
:chompy: :popcorn: | |
machty [11:42 AM] | |
maybe we make it possible to render the default / inverse blocks with `{{component}}` | |
[11:42] | |
but your component needs to be built one way or the other | |
[11:42] | |
if it classic yields: positional params, and no good way to bridge the gap with attr=(component) (edited) | |
[11:43] | |
it it component yields: the default template block would also be passed `|attrs|` | |
[11:43] | |
(and we'd need a syntax for `(component &default)`) (edited) | |
[11:43] | |
the wat is strong, but no more wat than the present situation (edited) | |
mmun [11:46 AM] | |
you can avoid a lot of design by simply going all in with yield and wrapping a component with block lambda. that qualifies as effortless to me. | |
machty [11:47 AM] | |
"do i have to" | |
mmun [11:48 AM] | |
namely: you can avoid designing an override for built in slots like &default, you can avoid thinking about the `positionalParams` api, and instead just mapping arguments | |
machty [11:48 AM] | |
ctrl-f translation layers https://github.com/machty/rfcs/blob/nested-handlebars/text/0000-nested-handlebars-syntax.md#why-not-yield-positional-params-vs-named-attrs | |
mmun [11:50 AM] | |
> First off, this assumes that we don't care that people have already written plenty of components in the header=(component ...) style; those people would have to rewrite both x-foo's internals and change any code that renders x-foo to support this. | |
We can provide tools to polyfill your component (edited) | |
machty [11:51 AM] | |
what's the polyfill? | |
[11:51] | |
`positionalParams` API? | |
mmun [11:52 AM] | |
{{#if (is-component header)}} | |
machty [11:52 AM] | |
... | |
[11:53] | |
if is-component header, then translate/reinterpret positional params into named things | |
[11:53] | |
internals still need to change to accommodate this | |
mmun [11:53 AM] | |
yes | |
[11:54] | |
either way internals have to change (because you need to define positional params) (edited) | |
[11:54] | |
unless you also want to design named arguments for blocks | |
machty [11:54 AM] | |
i think i've proposed the approach that such that this API is preserved | |
[11:54] | |
```{{x-foo | |
header=(component 'x-header' x=1) | |
body=(component 'x-body' y=2) | |
footer=(component 'x-footer' x=3) }} | |
``` | |
[11:54] | |
can you restate the argument that made you "rest your case"? | |
[11:55] | |
why do i have to design named arguments for blocks | |
[11:55] | |
i've pointed out the inconsistency and that it is an unfortunate artifact of the past and we should align towards a brighter future | |
[11:55] | |
two worlds exist today. they're incompatible. pick one. it'll hurt either way, but one is clearly superior IMO | |
mmun [11:56 AM] | |
exactly. | |
[11:56] | |
the superior one is the one everyone uses | |
[11:56] | |
blocks | |
[11:56] | |
grep how many people use {{yield}} vs {{component}} | |
machty [11:57 AM] | |
i dunno man i don't want to restate everything i argued in the RFC | |
mmun [11:57 AM] | |
your proposal is to continue with both {{yield}} AND {{component}} | |
machty [11:57 AM] | |
your way means translation layers and template-specific polyfill hacks that don't actually fully address the divide | |
[11:57] | |
so is yours | |
[11:57] | |
are you going to deprecate {{component}}? | |
mmun [11:58 AM] | |
no, i just imagine it will be used much more sparingly | |
machty [11:58 AM] | |
you answer is "i don't know what to do about {{component}}" and mine is "i don't know to do about {{yield}}" | |
mmun [11:58 AM] | |
where as {{#foo-bar}} ... {{/foo-bar}} is gonna be around for ever | |
machty [12:00 PM] | |
https://gist.github.com/machty/c00c83f3fbefefa72cefb0bb2322fc4f#slot-syntax | |
[12:00] | |
> We'd lose the pattern for global overrides app/ (yes, globals can always be abused, but they're great for establishing app-wide defaults while still leaving the door open for further overrides). The only way we could support "default block" templates in app/ would be to either add a syntax for declaring block params within the template (rather than at the tail end of a helper, e.g. {{#each ... as |blockParam|}}, or potentially by leveraging the esoteric positionalParams API so that "default blocks" would actually be default components that know how to convert positional block params to named attrs | |
[12:00] | |
yield would lose out on this pattern | |
[12:03] | |
there are other use cases / potentials that i haven't gone into | |
[12:03] | |
that have to do with Trek's vision of reusing/extending/overriding | |
[12:04] | |
whether it's component JS or hbs | |
[12:04] | |
that are _so close_ to being there with `{{component}}` but would need additional constructs with a yield-centric approach | |
[12:04] | |
i wish i could inundate you with examples but I cannot hack past the present glimmer limitations (edited) | |
machty [12:12 PM] | |
> so then if you want to remain compatible {{yield}} has to be able to yield to a component | |
[12:12] | |
more like: there will still be two ways to pass in overridable DOM today: one with classic block+yield, one with (component) and attrs | |
[12:13] | |
just as there are today | |
[12:13] | |
and components authors will still need to decide for what they're doing whether they're prefer the simple but limited yield + positional params approach | |
[12:13] | |
or they want to pass multiple things in (or plan one being able to do so in the future) | |
runspired [12:14 PM] | |
Y'all generate too much for me to reasonably read at this point :P | |
knownasilya [12:14 PM] | |
lol | |
[12:14] | |
summary: they are all saying the same thing, but in different ways, and a blindness to the other's direction :troll: | |
machty [12:15 PM] | |
it ain't so bad | |
[12:15] | |
we're caremad | |
[12:15] | |
at least i am | |
locks [12:15 PM] | |
and I just troll | |
[12:15] | |
we'll either end up implementing clojurescript or jsx | |
[12:15] | |
the jury is still out | |
runspired [12:15 PM] | |
Time for me to drop my reworked slots rfc i see ;) | |
[12:17] | |
Also @sclaxton if you're in SV today I should help you understand the Ember Component bs Web Component model better | |
locks [12:17 PM] | |
bullshit? | |
[12:18] | |
bootstrap? | |
[12:18] | |
beatle's song? (edited) | |
machty [12:18 PM] | |
wat | |
knownasilya [12:19 PM] | |
```{{my-modal &default=(|data| | |
full modal override {{data.one}} {{data.two}} | |
)}} | |
{{my-modal | |
head=(|data| | |
my header | |
) | |
body=(|data| | |
my body | |
) | |
}} | |
``` | |
interesting to see the readability issues, or how one indents and writes these, especially if multi lined | |
[12:21] | |
I'd probably do classic for full override | |
```{{#my-modal as |one two|}} | |
full modal override {{one}} {{two}} | |
{{/my-modal}} | |
``` | |
(edited) | |
locks [12:22 PM] | |
why so many newlines @knownasilya | |
knownasilya [12:23 PM] | |
```{{my-modal head=(|data| | |
my header | |
<a>close link</a> | |
) body=(|data| | |
my body | |
<a>link here too</a> | |
) | |
}} | |
``` | |
[12:23] | |
better? | |
[12:23] | |
:troll: | |
[12:23] | |
have fun reading that.. hopefully your editor can color it better then slack does | |
machty [12:24 PM] | |
how does bullshit pass the slackbot filter | |
mmun [12:24 PM] | |
im caremad | |
rwjblue [12:24 PM] | |
I'm carerage | |
machty [12:24 PM] | |
mmun is carestingonlaurels | |
mmun [12:24 PM] | |
what color do u wanna be machty? red or blue? | |
machty [12:25 PM] | |
plz tell me we're playing rocket league | |
mmun [12:25 PM] | |
we're playing photoshop | |
machty [12:25 PM] | |
you're gonna lose even if you have the popular vote | |
machty [12:26 PM] | |
uploaded this image: Pasted image at 2017-01-20, 12:25 PM | |
Add Comment | |
machty [12:26 PM] | |
i've already made it clear which color i am | |
mmun [12:26 PM] | |
that escalated quickly | |
knownasilya [12:27 PM] | |
looks like grey.. | |
mmun [12:27 PM] | |
haha, i see now. it isn't a political thing | |
knownasilya [12:27 PM] | |
checkered | |
machty [12:27 PM] | |
@knownasilya I can't tell if that code is an example for the RFC, or comparing w yield-centric syntax | |
mmun [12:27 PM] | |
we aren't making templates great again | |
knownasilya [12:28 PM] | |
@machty both? haha | |
locks [12:29 PM] | |
people, https://www.youtube.com/channel/UCII0hP2Ycmhh5j8lS4cexBQ | |
YouTube | |
Red vs. Blue | |
Welcome to the Red vs. Blue YouTube Channel. Home base for the web's longest running series, Rooster Teeth's award-winning Red vs. Blue. SUBSCRIBE: http://bi... | |
(edited) | |
knownasilya [12:29 PM] | |
Your RFC should also address formatting fallback | |
locks [12:29 PM] | |
what's formatting fallback? | |
knownasilya [12:29 PM] | |
wrong words.. /faceslap | |
[12:31] | |
what is the recommended way to format your component with this new syntax that goes in and out of handlebars syntax | |
machty [12:31 PM] | |
i'm still laughing at this exchange https://gist.github.com/machty/68afad4c03109f36d4f4cffaae3c170b#file-gistfile1-txt-L6217-L6220 | |
[12:32] | |
@knownasilya if i understand you correctly i think there's an example in the rfc | |
rwjblue [12:33 PM] | |
RFC should add "syntax highlighting" to drawbacks list | |
machty [12:33 PM] | |
confirm | |
rwjblue [12:33 PM] | |
(not a giant deal, since it would likely be a temp problem but something to mention nonetheless) (edited) | |
machty [12:34 PM] | |
i'll add that | |
locks [12:34 PM] | |
hey, wanna know a secret | |
machty [12:34 PM] | |
@knownasilya https://github.com/machty/rfcs/blob/nested-handlebars/text/0000-nested-handlebars-syntax.md#recursively-nestable-glimmerhandlebars-syntax | |
[12:34] | |
first example | |
[12:34] | |
has recursive nesting (edited) | |
locks [12:34 PM] | |
SH is already broken for ember templates | |
[12:34] | |
in most editors :P (edited) | |
rwjblue [12:35 PM] | |
@locks uhh, wat | |
[12:35] | |
"most" editors being which? | |
knownasilya [12:35 PM] | |
@machty need an example with multiple anon-components | |
rwjblue [12:35 PM] | |
because it works well in vim, emacs, webstorm, vscode, sublime text 2, at least (these are the ones I have used in the last 3 months).... | |
knownasilya [12:36 PM] | |
or inline-components, what's the name? | |
1 reply Today at 12:37 PM View thread | |
locks [12:36 PM] | |
I have a document _somewhere_ with this | |
[12:36] | |
for the tools page of emberwatch | |
knownasilya [12:36 PM] | |
not nested, but siblings | |
rwjblue [12:36 PM] | |
@locks ya, no biggie, just curious (we should side channel this to #topic-editors though) | |
2 replies Last reply today at 12:39 PM View thread | |
locks [12:36 PM] | |
yy | |
machty [12:37 PM] | |
added this Markdown (raw) snippet: nested af | |
{{x-foo | |
header=(|d| | |
I am a fragment {{d.title}} | |
<span>Woot</span> | |
) | |
body=(|d| | |
I am a fragment {{d.title}} | |
<span>Woot</span> | |
{{x-foo | |
header=(|d| | |
I am a fragment {{d.title}} | |
<span>Woot</span> | |
) | |
body=(|d| | |
I am a fragment {{d.title}} | |
<span>Woot</span> | |
) | |
footer=(|d| | |
I am a fragment {{d.title}} | |
<span>Woot</span> | |
) | |
}} | |
) | |
footer=(|d| | |
I am a fragment {{d.title}} | |
<span>Woot</span> | |
) | |
}} | |
Add Comment Collapse | |
machty [12:37 PM] | |
@knownasilya ^ | |
knownasilya [12:38 PM] | |
yeah, add that | |
machty [12:38 PM] | |
i think i'm gonna add an appendix of sorts (edited) | |
[12:38] | |
random code snippets that reinforce the RFC and tickle the imagination | |
rwjblue [12:38 PM] | |
ohhh, can we add a new subheading to RFC's? | |
knownasilya [12:38 PM] | |
tickle the imagination, what a slogan | |
rwjblue [12:38 PM] | |
"Ticklers" | |
knownasilya [12:39 PM] | |
lol | |
locks [12:39 PM] | |
that's against the CoC @rwjblue | |
[12:39] | |
and like shaving, you never go against the CoC | |
knownasilya [12:39 PM] | |
ToS? | |
rwjblue [12:39 PM] | |
locks I think that abbreviation is too then... | |
locks [12:39 PM] | |
I think about that every single time I see it | |
rwjblue [12:39 PM] | |
I was thinking of like a feather duster, where is your head at? | |
knownasilya [12:39 PM] | |
@machty need an example with using a block and anon-components | |
locks [12:40 PM] | |
how oblivious can you be | |
rwjblue [12:40 PM] | |
@machty nice :slightly_smiling_face: | |
knownasilya [12:40 PM] | |
like @rtablada posted | |
machty [12:40 PM] | |
set the channel topic: machty's component/yield RFC: https://github.com/emberjs/rfcs/pull/203 | |
Backlog manually persisted here: | |
<https://gist.github.com/machty/68afad4c03109f36d4f4cffaae3c170b> | |
rwjblue [12:40 PM] | |
We should figure out a new name for the channel though | |
machty [12:40 PM] | |
not just yet | |
rwjblue [12:40 PM] | |
`#-machtys-musings` | |
2 replies Last reply today at 12:41 PM View thread | |
knownasilya [12:41 PM] | |
#machtys-ideas (edited) | |
locks [12:41 PM] | |
I already suggested #weaksauce | |
rwjblue [12:41 PM] | |
hmm, I wonder what the pluralization of @machty is actually | |
locks [12:41 PM] | |
it's @machty | |
[12:42] | |
it's also the past tense of the verb @machty (edited) | |
machty [12:48 PM] | |
uploaded this image: Pasted image at 2017-01-20, 12:48 PM | |
Add Comment | |
machty [12:48 PM] | |
it even conveniently highlights the closing curlies | |
[12:48] | |
:troll: | |
rwjblue [12:48 PM] | |
lol | |
mmun [12:50 PM] | |
@machty if your rfc lands, do you envision people will stop using {{#my-component}}block{{/my-component}} and migrate to lambda attrs for everything? | |
machty [12:51 PM] | |
maybe the result is that "control-flow-y" components stick w positional params + traditional default block (edited) | |
mmun [12:51 PM] | |
let me refine my question | |
[12:52] | |
do we expect people to use both plain-old-blocks and lambda attrs on a single component (edited) | |
machty [12:52 PM] | |
i don't think so | |
[12:52] | |
i hope not | |
mmun [12:52 PM] | |
power-select is currently designed this way | |
knownasilya [12:52 PM] | |
```{{each users &default=(|data| <p>{{data.name}}</p>)}} | |
``` | |
(edited) | |
machty [12:54 PM] | |
yeah i don't think each is a good candidate for this new syntax | |
[12:54] | |
but say if you're writing a calendar component and you wanna pass the `day-cell` component into it, then it's pretty good | |
[12:54] | |
since day-cell is just one of the things you might want to configure | |
mmun [12:55 PM] | |
fwiw, I think most people think of each & if as built-in syntax and it's totally fine to be different (edited) | |
[12:56] | |
in power-select, 90% of the time you just want to customize the text that is shown for each option (edited) | |
[12:56] | |
so the default block is optimized for that | |
knownasilya [12:56 PM] | |
yeah ^ | |
mmun [12:57 PM] | |
i would even be mad if there was a version of power-select that was attrs-only though. i see it as a minor style thing. (edited) | |
machty [12:57 PM] | |
i actually disagree with that | |
knownasilya [12:57 PM] | |
```{{power-select options=options | |
selected=selected | |
onchange=(action (mut selected)) | |
selectedItemComponent=(|data| <span class="flex">{{data.name}}</span>) | |
itemDisplayComponent=(|data| {{data.name}}) | |
}} | |
``` | |
(edited) | |
machty [12:59 PM] | |
i think because the present situation limits you to only one lambda block (the main/default), component authors have had to choose which overridable slot is best represented as the default, and all else is relegated to being overridable by attrs (that either point to raw values or (component)s) | |
knownasilya [12:59 PM] | |
or is it {{data.item.name}}.. | |
[12:59] | |
@machty I agree | |
[12:59] | |
and it's usually a relative decision.. | |
machty [12:59 PM] | |
whether we introduce the yield-centric slots RFCs that people have submitted or my RFC, people will start thinking differently / more creatively | |
mmun [1:00 PM] | |
what's the part you disagree with? | |
[1:00] | |
i agree with what you said 100% | |
machty [1:01 PM] | |
i disagree that it's obvious for ember-power-select that assume that the search results be the "winner" | |
[1:01] | |
who sits on the default block throne | |
[1:01] | |
it's just that there's been no other way to think about it in the past | |
mmun [1:02 PM] | |
i agree. i was just describing the status quo above. didn't mean to suggest it is great. | |
[1:02] | |
default/inverse blocks work very well for if/each but not for components. same as positional params. it's probably not a coincidence! (edited) | |
[1:05] | |
```{{let liWrapper=(|item| <li>{{yield item}}</li>)}} | |
{{#each-wrapper items wrapper=liWrapper as |item|}} | |
{{item.name}} | |
{{/each-wrapper}} | |
``` | |
(edited) | |
[1:05] | |
i can sorta imagine situations where you might want to use both plain-old-blocks and lambdas | |
[1:06] | |
mostly for when you're trying to emulate something that should feel like an each/if | |
[1:06] | |
but typical application components I can see myself using lambdas only | |
machty [1:30 PM] | |
this rfc's gonna be bad for my health | |
locks [1:31 PM] | |
mine too | |
[1:31] | |
we're in this together now | |
machty [1:31 PM] | |
lol are we? i can't tell if i've convinced anyone but myself | |
knownasilya [1:32 PM] | |
I like it :slightly_smiling_face: | |
mmun [1:33 PM] | |
i'm interested to get feedback from ed and kris | |
machty [1:33 PM] | |
moving it into FCP | |
locks [1:34 PM] | |
I'll merge | |
knownasilya [1:34 PM] | |
lol | |
locks [1:35 PM] | |
what about `let` :( | |
knownasilya [1:35 PM] | |
yeah both | |
[1:35] | |
:+1::+1: | |
[1:38] | |
solution to big inline blocks.. | |
rwjblue [1:38 PM] | |
@machty hmm, I think I told you I am convinced of the larger point? | |
[1:38] | |
IMO the important part is support for nesting, and a way to invoke passed blocks | |
[1:39] | |
your proposal seems fine as far as it goes, but there are many details still to be fleshed out | |
knownasilya [1:39 PM] | |
```{{let itemDisplay=(|data| <span class='item'>{{data.name}}</span>)}} | |
{{power-select ... itemDisplayComponent=itemDisplay}} | |
more forms | |
{{power-select ... itemDisplayComponent=itemDisplay}} | |
more forms | |
{{power-select ... itemDisplayComponent=itemDisplay}} | |
``` | |
mmun [1:40 PM] | |
i think it's important even to just rally the community around https://embercommunity.slack.com/archives/topic-forms/p1484937536003344 instead of a slot-based solution | |
rwjblue | |
IMO the important part is support for nesting, and a way to invoke passed blocks | |
Posted in #topic-formsToday at 1:38 PM | |
(edited) | |
locks [1:40 PM] | |
I'm trying not to troll with ruby's symbol to proc short hand (edited) | |
rwjblue [1:41 PM] | |
@mmun confirm (edited) | |
locks [1:41 PM] | |
I also agree with the need for the primitives | |
rwjblue [1:41 PM] | |
that part alone was a big AHA for me | |
machty [1:41 PM] | |
@knownasilya confirm, slot syntax doesn't solve the use case of passing the same block to multiple components (edited) | |
rwjblue [1:41 PM] | |
though I haven't _really_ done react so hadn't been exposed to JSX specifics much | |
machty [1:50 PM] | |
set the channel topic: component/yield RFC: <https://github.com/emberjs/rfcs/pull/203> | |
Backlog manually persisted here: | |
<https://gist.github.com/machty/68afad4c03109f36d4f4cffaae3c170b> | |
sclaxton [1:53 PM] | |
I like the arbitrary nesting of template as data, but worried it sacrifices our current model of template as semantic markup at the altar of consistency (cf. my comment on @machty’s rfc) | |
[1:53] | |
it certainly makes things more flexible, but also less structured | |
[1:53] | |
which makes sense, since the two are usually at odds | |
[1:54] | |
but this seems like lots of yin and no yang, mang (edited) | |
knownasilya [1:55 PM] | |
I don't think it's just for consistency, that's secondary really | |
sclaxton [1:55 PM] | |
it was most of the RFC heh | |
knownasilya [1:55 PM] | |
yeah, maybe some wording has to be changed about why it's usefuly, not being so defensive | |
locks [1:55 PM] | |
I'm sensing different definitions of consistency | |
sclaxton [1:56 PM] | |
“impedance mismatch” = a consistency argument | |
[1:56] | |
and “impedance mismatch” was thrown around a lot in the RFC | |
knownasilya [1:57 PM] | |
@machty might be worth mentioning the let rfc as a tag along (edited) | |
[1:57] | |
or something that would work well together | |
sclaxton [1:57 PM] | |
I 100% percent agree it’s useful | |
[1:58] | |
but lots of things are useful | |
[1:58] | |
I’m just not convinced I want us to go full template-as-data route | |
locks [1:59 PM] | |
that's what templates are | |
machty [1:59 PM] | |
i ramped defensiveness up to 9 | |
sclaxton [2:00 PM] | |
no currently templates are more markup than data | |
[2:01] | |
by data I mean stuff that you can pass around as arbitrarily as primitive data | |
machty [2:17 PM] | |
added an examples section https://github.com/machty/rfcs/blob/nested-handlebars/text/0000-nested-handlebars-syntax.md#appendix-examples | |
[2:18] | |
I feel like nothing that is bad/missing about react is due to the first-class-everything-is-a-component API | |
[2:19] | |
the lack of conventions in React that hurt the most surround state mgmt/context/etc | |
sclaxton [2:20 PM] | |
agree | |
[2:21] | |
but reacts more functional programming model in general is more suited to that API (edited) | |
machty [2:21 PM] | |
what about ember/glimmer isn't? (other than we have yet to embrace it) | |
sclaxton [2:22 PM] | |
I mean we could become react? | |
knownasilya [2:22 PM] | |
@sclaxton you can pass them around, see ember-elsewhere and any other addons that use a service to move components from one place to another | |
sclaxton [2:23 PM] | |
pass them around like primitive data | |
knownasilya [2:23 PM] | |
pretty much there, like 85% | |
[2:24] | |
arbitrary percentage lol | |
sclaxton [2:24 PM] | |
I’d say 40% | |
[2:24] | |
maybe | |
[2:24] | |
anonymous blocks + this RFC would get us to 90% tho haha (edited) | |
[2:26] | |
and moving things from one place to another in the dom has nothing to do with passing around template like you would primitive data | |
[2:27] | |
that’s just an application of being able to pass it around | |
[2:27] | |
so it guess it has something to do , but yah, just an application | |
knownasilya [2:28 PM] | |
```{{#my-comp someOtherComp=(component 'my-comp-extension') as |ui|}} | |
{{other-comp comp=ui.someOtherComp}} | |
{{/my-comp}} | |
``` | |
looks like passing data around.. | |
sclaxton [2:28 PM] | |
yep it is | |
[2:28] | |
but with arbitrary data you can pass it as literals | |
knownasilya [2:28 PM] | |
shown as block to avoid making multiple tempaltes, obviously a convoluted example | |
sclaxton [2:28 PM] | |
which is what anonymous blocks would essentially guess | |
[2:28] | |
passing template literals | |
[2:30] | |
@machty we also still maintain a strict separation between template and js | |
[2:30] | |
which makes treating template fully as data more painful for us than for react | |
[2:31] | |
also our templating lang isn’t a superset of a turing complete programming language (edited) | |
[2:31] | |
list goes on | |
locks [2:31 PM] | |
thank god | |
sclaxton [2:32 PM] | |
same | |
[2:32] | |
I think there are a number of reasons why template as data works better for react than it would for us | |
[2:33] | |
their baked in focus on immutability is another reason (edited) | |
knownasilya [2:35 PM] | |
nothing about immutability in react is baked in.. | |
machty [2:35 PM] | |
added an example integrating w `let` RFC: https://github.com/machty/rfcs/blob/nested-handlebars/text/0000-nested-handlebars-syntax.md#using-in-conjunction-with-let-rfc /cc @cowboyd | |
knownasilya [2:35 PM] | |
wish it was, it's pretty annoying | |
sclaxton [2:36 PM] | |
well I guess I mean if you’re using immutable.js | |
machty [2:36 PM] | |
@sclaxton i don't think anything i'm suggesting breaks the strict separation b/w js/hbs | |
sclaxton [2:36 PM] | |
like they support immutability first clsas | |
machty [2:37 PM] | |
Glimmer/hbs is still declarative even if we make templates first class values that can be passed around | |
knownasilya [2:37 PM] | |
yeah and immutable.js is probably more confusing API wise then ember-data :confused: | |
sclaxton [2:37 PM] | |
@machty it doesn’t but I was just saying that makes something liek this easier for react | |
machty [2:37 PM] | |
i think that's only because we simply haven't developed such features | |
[2:37] | |
it's not fundamentally "easier" for react | |
[2:37] | |
we just haven't adopted that pattern yet | |
[2:37] | |
it doesn't even make "more sense" for react | |
sclaxton [2:38 PM] | |
template being a superset of turing complete language doesn’t make it easier? (edited) | |
[2:39] | |
and the fact that that turing complete language happens to be the language as your js component | |
[2:42] | |
I have a hard time believing it would be as easy for us as react just because of the properties of JSX | |
[2:43] | |
vs the properties of HBS | |
[2:43] | |
but also I’m majorly playing devils advocate here, fyi (edited) | |
samselikoff [2:46 PM] | |
btw, i’ve personally needed “template-as-data” two or three times in the past two weeks, and i resort to some data-catcher nonsense to get it | |
knownasilya [2:46 PM] | |
Feel the same way ^ | |
samselikoff [2:47 PM] | |
```{{yield ( | |
subnav-item=(component 'data-catcher' on-insert=(action 'registerSubnavItem')) | |
)}} | |
``` | |
sclaxton [2:47 PM] | |
interesting | |
[2:47] | |
curious about your use case | |
samselikoff [2:47 PM] | |
then the component can `{{each}}` over the data itself | |
sclaxton [2:47 PM] | |
could it have also been solved with named slots + contextual components | |
samselikoff [2:48 PM] | |
would have to think more on that. | |
[2:48] | |
```{{#topbar.app-nav as |nav|}} | |
{{nav.item routeName="app-nav.one-fish" label="One fish"}} | |
{{#nav.subnav label="Two fish" as |subnav|}} | |
{{subnav.item routeName="app-nav.two-fish.black-fish" label="Black fish"}} | |
{{subnav.item routeName="app-nav.two-fish.blue-fish" label="Blue fish"}} | |
{{subnav.item routeName="app-nav.two-fish.old-fish" label="Old fish"}} | |
{{subnav.item routeName="app-nav.two-fish.new-fish" label="New fish"}} | |
{{/nav.subnav}} | |
{{nav.item routeName="app-nav.red-fish" label="Red fish"}} | |
{{nav.item routeName="app-nav.blue-fish" label="Blue fish"}} | |
{{/topbar.app-nav}} | |
``` | |
(edited) | |
[2:48] | |
it’s basically if I have something like this, and I want to make `<app-nav>` use this listing to make a desktop and mobile version of the nav | |
[2:48] | |
you could ask the caller to specify all this in a JS array | |
[2:48] | |
but you can see that it’s really more appropriate for this to be in the template | |
[2:49] | |
it’s really a data structure | |
[2:49] | |
and i just want to capture the data structure, massage it and display it in a certain way | |
sclaxton [2:50 PM] | |
that’s what I’m really interested in, what important use cases does slots + contextual components miss out on | |
mmun [2:50 PM] | |
block lambdas gives you an obvious solution for this | |
sclaxton [2:50 PM] | |
werd | |
mmun [2:50 PM] | |
vs. a dynamic slots approach | |
sclaxton [2:51 PM] | |
that’s another thing I wonder about, are slots and lambdas interchangable? (edited) | |
mmun [2:51 PM] | |
```items=(array | |
(|| Red fish) | |
(|| Blue fish) | |
) | |
``` | |
sclaxton [2:51 PM] | |
use case wise | |
samselikoff [2:51 PM] | |
`<app-nav>` component basically ends up doing something like this | |
```{{#each item.subnavItems as |item|}} | |
{{app-nav/mobile-nav-item navItem=item | |
on-click=(action 'closeMobileNavAndNavigate')}} | |
{{/each}} | |
``` | |
[2:52] | |
yah but | |
[2:52] | |
don’t just want an array. what if they want to add an `{{fa-icon}}` as their label | |
[2:52] | |
```{{#nav.item routeName="app-nav.red-fish"}} | |
Red fish {{fa-icon 'fish'}} | |
{{/nav.item}} | |
``` | |
(edited) | |
[2:52] | |
thats why i think it belongs in template | |
machty [2:54 PM] | |
@sclaxton i definitely don't want hbs/glimmer to be turing complete. i'm proposing making it more powerful within the bounds of declarative / side-effect free constraints | |
[2:56] | |
there are features that demonstrate the power of the declarative Glimmer model (where we teach Glimmer where data is coming from and how it updates) that we are not taking advantage of because features are missing | |
[2:56] | |
the features i'm proposing my Glimmer flex its power even more than it already does | |
[2:56] | |
without breaking any fundamental mental models / side-effect-free / declarative foundations | |
sclaxton [2:59 PM] | |
I mean this breaks this major mental model of “a component is like some custom markup that exists within the structure of my plain html document" (edited) | |
[2:59] | |
but maybe that mental model isn’t important to us anymore? (edited) | |
[2:59] | |
that’s what I’m trying to gauge with my devils advocate bull ish (edited) | |
slackbot Custom Response [2:59 PM] | |
:explicitwarning: We'd love for this to remain an awesome place for all Emberers. Helps us out by editing that message. :point_up: https://github.com/cromwellryan/embercommunity-slack-guidelines/blob/master/CodeOfConduct.md | |
machty [3:03 PM] | |
```{{let foo=(|d| | |
Hello {{d.a}}, {{d.b}}, and {{d.c}}! | |
)}} | |
<my-component header={{foo}} body={{foo}} /> | |
``` | |
[3:03] | |
the inline syntax examples that i lead with are just a syntactic nicety that expresses the same as the above | |
sclaxton [3:04 PM] | |
I like this better | |
[3:05] | |
but I still feel like we lose a little of the structure that’s nice with current components | |
machty [3:05 PM] | |
(this also happens to be an example of a use case left unsolved by slot syntax: passing the same block to multiple attrs / components) | |
sclaxton [3:07 PM] | |
not sure what you mean by “slots can’t pass the same block to multiple attrs/components" | |
machty [3:07 PM] | |
```{{#some-component}} | |
This is the default, un-named block | |
{{:block-a as |block|}} | |
This is block {{block}} | |
{{:block-b as |block|}} | |
This is block {{block}} | |
{{/some-component}} | |
``` | |
[3:08] | |
if i wanted to pass the exact same thing to block-a and block-b i would need to duplicate code | |
[3:08] | |
the entire block would need to be duplicated (edited) | |
sclaxton [3:08 PM] | |
why can’t you use `let` the same way you did in your example | |
machty [3:08 PM] | |
with the `let` approach i can define once, pass to both | |
[3:09] | |
oh, well, you could | |
sclaxton [3:09 PM] | |
I really like the power of let + lambdas | |
[3:09] | |
like 100% | |
[3:10] | |
jury is still out on slot vs machty components (edited) | |
machty [3:11 PM] | |
:+1: | |
sclaxton [3:12 PM] | |
discussion has been great tho. so even if this rfc doesn’t make it, was def worth | |
machty [3:12 PM] | |
i feel that way too | |
[3:13] | |
i could make vague complaints about the cognitive dissonance (as you described) that i feel a lot about ember APIs, but nothing like an RFC to get people to really think about it / address it (edited) | |
machty [3:21 PM] | |
set the channel topic: component/yield RFC: https://github.com/emberjs/rfcs/pull/203 | |
Backlog manually persisted here: | |
<https://gist.github.com/machty/68afad4c03109f36d4f4cffaae3c170b> | |
rwjblue [3:22 PM] | |
why you keep doing that? | |
[3:22] | |
to notify of logging? | |
jrowlingson [3:23 PM] | |
i think thats against the slack TOS | |
rwjblue [3:23 PM] | |
not sure, I think bots are against the ToS | |
[3:23] | |
he is doing it manually | |
machty [3:23 PM] | |
my last attempt to set it made it include a closing angle bracket in the link | |
rwjblue [3:23 PM] | |
unless they suggest that copy / pasting is against ToS | |
machty [3:23 PM] | |
i think there's a bug with updating the header and preserving a link that was already in there | |
rwjblue [3:24 PM] | |
which is pretty WAT | |
[3:24] | |
@machty weird? | |
machty [3:24 PM] | |
sorry for the noise | |
rwjblue [3:24 PM] | |
haha, its all noise! | |
[3:24] | |
like that rock and roll the kids listen to these days | |
[3:25] | |
:stuck_out_tongue: | |
----- Today January 21st, 2017 ----- | |
locks [7:14 AM] | |
https://www.sitepoint.com/using-inline-partials-and-decorators-with-handlebars-4-0/ | |
SitePoint | |
Using Inline Partials and Decorators with Handlebars 4.0 | |
Ryan Lewis teaches you how to use Inline Partials and Decorators in your own projects employing Handlebars 4.0. | |
Jan 27th, 2016 at 8:00 AM | |
[7:17] | |
hbs 4 is _whack_ | |
knownasilya [8:47 AM] | |
sure is wack.. | |
locks [8:51 AM] | |
did one of you link to https://www.youtube.com/watch?v=GXcDQK678_E ? | |
YouTube Ember Videos | |
EmberCamp London 2015: : The Hidden Power of HTMLBars by Matthew Beale | |
[8:51] | |
i's let-related | |
locks [8:53 AM] | |
uploaded this image: Screen Shot 2017-01-21 at 13.52.36.png | |
Add Comment | |
rwjblue [10:38 AM] | |
seems a bit O_o, but we could definitely leverage the syntax for `{{let-block` if we wanted to... | |
[10:41] | |
```{{! define the block }} | |
{#*inline "content-block"}} | |
My new content | |
{{/inline}} | |
{{> content-block}} {{! render it!}} | |
``` | |
machty [11:50 AM] | |
Wow didn't know about that | |
rwjblue [11:52 AM] | |
@machty well, glimmer is only using Handlebars 3, but @tbieniek and locks have been working on upgrading to Handlebars 4 | |
[11:53] | |
The blocker to landing the Handlebars 4 PR is that we are going to explicitly throw when we see these inline partials, decorators, etc | |
[11:54] | |
but it would be easy to fiddle with things to see about it actually working | |
locks [12:16 PM] | |
It's not recursive, is it? | |
machty [3:07 PM] | |
breaking my brain imaging how it could be | |
locks [4:39 PM] | |
And isn't your rfc? | |
[4:39] | |
I think I mean nesting, but more than one level | |
machty [5:15 PM] | |
i guess it isn't that brain breaking to imagine how the inline partials could be nested | |
machty [5:21 PM] | |
(my rfc definitely is) | |
machty [5:26 PM] | |
https://github.com/wycats/handlebars.js/blob/master/spec/partials.js#L328 | |
[5:26] | |
https://github.com/wycats/handlebars.js/pull/1290 | |
[5:26] | |
i still haven't confirmed that i've seen an inline partial _in_ an inline partial (edited) | |
[5:26] | |
this are close | |
[5:27] | |
but still no inline within inline | |
[5:28] | |
> After thinking about it a lot (this is kind of a brain-twister), I've come to the conclusions that partial-blocks should be treated like function-closures: | |
[5:28] | |
welcome to the club | |
mmun [5:32 PM] | |
man it really frustrates me how much syntax landed without cooperation of ember | |
locks [5:45 PM] | |
is hbs still string-based? | |
machty [5:47 PM] | |
probz | |
[5:47] | |
that repo's weird | |
[5:47] | |
it houses both the gold standard of the specification while also providing the javascript implementation | |
sclaxton [5:51 PM] | |
@mmun didn’t you start a separate hbs spec repo? | |
[5:51] | |
what’s the status on that | |
locks [5:52 PM] | |
something something mustache/spec | |
locks [5:52 PM] | |
is the maintainer of mustache :skull: | |
sclaxton [5:52 PM] | |
I think this was a fork of the mustache spec | |
machty [5:52 PM] | |
@sclaxton https://github.com/emberjs/rfcs/pull/203#issuecomment-274288879 | |
[5:53] | |
this guy's (and i can only assume everyone-else-on-the-planet's) gut reaction is that i'm proposing callback hell | |
[5:53] | |
i wonder if there's a way your slot syntax would help | |
[5:53] | |
your slot syntax and my proposed component-centric semantics (edited) | |
locks [5:53 PM] | |
because people pass 20 actions to components | |
sclaxton [5:54 PM] | |
tru | |
mmun [5:54 PM] | |
Yes. Its on thr back burner | |
locks [5:54 PM] | |
and either every single attribute of a model, or the model itself | |
sclaxton [5:54 PM] | |
^this is what I think slots might discourage | |
[5:54] | |
which is a huge win | |
locks [5:54 PM] | |
meh | |
sclaxton [5:54 PM] | |
or machty’s rfc | |
[5:54] | |
either one (edited) | |
mmun [5:54 PM] | |
Wow its on callback hell at all | |
[5:55] | |
Blocks are immediately invoked. | |
sclaxton [5:55 PM] | |
why meh @locks ? | |
mmun [5:55 PM] | |
Guess i should read his comment first tho | |
machty [5:55 PM] | |
i suddenly got extremely confused about what people are talking about | |
locks [5:55 PM] | |
@sclaxton you're either overestimating or underestimating people ;P | |
sclaxton [5:55 PM] | |
probably tru | |
[5:56] | |
but it would at least provide a path to pass in less attrs | |
locks [5:56 PM] | |
callback hell -> rightwards drift? | |
machty [5:56 PM] | |
@sclaxton in my mind, blocks and names blocks are attrs / passed-in-data all the same, just that we've sneakishly put them in a separate namespace so that they don't appear to be | |
[5:57] | |
hence `hasBlock.hbs` and `hasBlock.js` RFC and all the unforeseen use cases that come out of the woodwork when we try and hide useful data from people (edited) | |
sclaxton [5:57 PM] | |
mmm I disagree that they’re all attrs | |
[5:57] | |
I think `{{component}}` has blurred that line | |
[5:58] | |
which is either good or bad | |
[5:58] | |
I think blocks shouldn’t be accessible for inspection in js | |
[5:58] | |
and attrs should | |
machty [5:58 PM] | |
:rage4: | |
sclaxton [5:59 PM] | |
I could be convinced otherwise :slightly_smiling_face: | |
mmun [5:59 PM] | |
I agree with machty strongly :p | |
sclaxton [5:59 PM] | |
but that’s just my current thinking | |
[6:00] | |
so we should be able to do arbitrary logic manipulating blocks? | |
[6:00] | |
in js | |
locks [6:00 PM] | |
people already do | |
mmun [6:00 PM] | |
It should work like ruby. | |
sclaxton [6:01 PM] | |
I mean true, but should they was the question | |
mmun [6:01 PM] | |
You can hold on to a block but if you dont satisfy the invariants you're gonna get exceptions. This the price we pay for using a dynamic language | |
sclaxton [6:01 PM] | |
what’s the point of logic-less templates if you can do arbitrary logic to play around with blocks | |
locks [6:01 PM] | |
they're not logic-less | |
[6:02] | |
I need to pester yehuda to talk about this | |
mmun [6:02 PM] | |
That is a nonsequtior | |
sclaxton [6:02 PM] | |
logic-limited | |
new messages | |
[6:02] | |
hmmm is it? | |
mmun [6:02 PM] | |
Logic is not a factor. | |
[6:02] | |
Declarativeness is the only factor | |
sclaxton [6:02 PM] | |
ok true | |
[6:03] | |
I guess my gut is telling me allowing block manipulation in js would break some amount of declarativeness? | |
mmun [6:03 PM] | |
Are you familiar with LocalJumpError in ruby? | |
sclaxton [6:03 PM] | |
need to think more tho | |
[6:04] | |
like you’re moving template related concerns into js | |
mmun [6:04 PM] | |
https://ruby-doc.org/core-2.2.2/LocalJumpError.html | |
ruby-doc.org | |
Class: LocalJumpError (Ruby 2.2.2) | |
Class : LocalJumpError - Ruby 2.2.2 | |
[6:04] | |
The second example is the relevant one | |
sclaxton [6:04 PM] | |
so to understand how a template renders you have to go to both js and hbs no? | |
[6:05] | |
you’re right, I said logic when I meant declarative lol | |
[6:05] | |
oops | |
mmun [6:06 PM] | |
1. No one is suggesting that blocks be mutable | |
sclaxton [6:06 PM] | |
but you could swap out blocks and stuff no? | |
[6:07] | |
if they’re just attrs | |
[6:07] | |
not actually mutate | |
[6:07] | |
but reassign | |
mmun [6:07 PM] | |
Yes you could | |
locks [6:07 PM] | |
as you can now | |
sclaxton [6:07 PM] | |
thats seems lame | |
[6:07] | |
you can mutate components attrs | |
[6:07] | |
not bloks | |
mmun [6:08 PM] | |
Yes it is but i dont follow your argument | |
machty [6:08 PM] | |
added this Markdown (raw) snippet: machty semantics with sclaxton syntax | |
sclaxton syntax: new slot syntax (rather than nested JSX-y machty syntax) | |
machty semantics: the named slots actually get passed in as attrs, and are renderable via {{component}} | |
{{#x-foo other=data | |
:header as |a|}} | |
Add Comment Click to expand inline 28 lines | |
locks [6:08 PM] | |
and you can manually append components | |
machty [6:08 PM] | |
@sclaxton let us smoke a peace pipe on ^ | |
mmun [6:08 PM] | |
Why are you introducing a JS file when you can do itwithin a template? | |
sclaxton [6:08 PM] | |
@mmun i’m just saying that’s why I don’t think blocks should be attrs? (edited) | |
locks [6:08 PM] | |
what's : again | |
machty [6:08 PM] | |
https://github.com/sclaxton/rfcs/blob/master/text/0000-named-blocks-and-yields.md | |
mmun [6:09 PM] | |
Your argument doesnt make sense to me. You can make a CP that toggles between two passed in attr values | |
[6:09] | |
You can also just do this logic in tge template which is preferable (edited) | |
sclaxton [6:10 PM] | |
right, but we’d be providing both paths | |
locks [6:10 PM] | |
I want to reiterate that we already do | |
mmun [6:10 PM] | |
That is a fundamental part of ember components and has nothing to do with the values being blocks or not (edited) | |
[6:11] | |
Why special case blocks | |
sclaxton [6:11 PM] | |
hmm I think mb I just don’t have a clear picture of machy meant by all blocks should be attrs | |
[6:11] | |
so we’re on different pages | |
mmun [6:13 PM] | |
I hope everyone agrees that keeping declarative view logic in the template is desirable when possible (edited) | |
sclaxton [6:14 PM] | |
passing blocks and components the same way you pass data still doesn’t sit well with me (edited) | |
[6:14] | |
even tho I fully recognize it’s very useful | |
[6:14] | |
like VERY | |
mmun [6:15 PM] | |
Lol | |
machty [6:15 PM] | |
that viewpoint only makes sense to me if you think `header=(component ...)` is a bad pattern (edited) | |
sclaxton [6:15 PM] | |
that’s what I’m saying | |
machty [6:15 PM] | |
oof | |
locks [6:15 PM] | |
if we want to turn handlebars into lisp, we need to get on board with code is data is code | |
sclaxton [6:15 PM] | |
I don’t think it’s a bad pattern per say | |
[6:16] | |
I think once you accept it, it leads to many useful patterns | |
mmun [6:16 PM] | |
You need to qualify what doesnt sit well with you | |
sclaxton [6:16 PM] | |
sure | |
mmun [6:17 PM] | |
And you should do so assuming there's no component.js file | |
sclaxton [6:17 PM] | |
it’s hard to tell when an attr is primitive data and when it is a piece of template | |
[6:17] | |
cause attrs are just attrs | |
mmun [6:18 PM] | |
I agree with that. | |
sclaxton [6:18 PM] | |
and if you have 20 attrs and they’re intermingling pieces of layout and primitive data it feels weird | |
mmun [6:19 PM] | |
Do you think its weird when you make an ajax call that you pass a primitive string URL and a callback? | |
locks [6:19 PM] | |
if you have 20 attrs you have other problems | |
mmun [6:19 PM] | |
Because this isnt any different | |
[6:19] | |
I suspect that you just dont like untyped languages :p | |
locks [6:20 PM] | |
but… with TS… you can… :D | |
machty [6:20 PM] | |
(having a convenient multiple-blocks + closed over scope API would put a downward pressure on the number of attrs that need to be passed in to otherwise express certain complicated components) (edited) | |
sclaxton [6:21 PM] | |
I feel like it’s different because attrs belong to both the js world and the template world but I feel like pieces of template should only belong to template world | |
[6:21] | |
does that make sense? | |
[6:21] | |
totally down to be convinced otherwise tho | |
machty [6:22 PM] | |
it seems like a healthy compromise that template blocks be accessible but read-only in JS | |
[6:22] | |
(which they would be w this RFC, and they are today with `attr=(component ...)`) (edited) | |
sclaxton [6:23 PM] | |
Maybe it’s not even which world they belong to, but being able to tell it’s a template | |
mmun [6:23 PM] | |
How is that a problem? There isnt to worlds. Only javascript. | |
sclaxton [6:24 PM] | |
hbs isn’t just js? | |
[6:24] | |
to users | |
mmun [6:25 PM] | |
If you want to believe that you must atleast allow for opaque values to escape the template layer and return. | |
[6:26] | |
I dont see any philisophical problem with that. | |
sclaxton [6:27 PM] | |
philosophically there is not | |
[6:27] | |
you’re right | |
[6:27] | |
theoretically this all makes sense | |
[6:27] | |
I guess I’m more worried about the attr soup @locks was talking about | |
machty [6:27 PM] | |
I'd like to see the mental model / coding hazards that occur due to letting JS have access to opaque template blocks generated from Hbs. Otherwise we're not gonna get anywhere with "it just feels like they should be separate" | |
mmun [6:28 PM] | |
https://embercommunity.slack.com/archives/topic-forms/p1485040817003670 | |
machty | |
(having a convenient multiple-blocks + closed over scope API would put a downward pressure on the number of attrs that need to be passed in to otherwise express certain complicated components) | |
Posted in #topic-formsJan 21st at 6:20 PM | |
[6:28] | |
Can you unroll that for me? I didnt understand | |
sclaxton [6:28 PM] | |
if we make discourage the use of hierarchically structured template definition in favor of passing everything as an attr, that’s just more attr soup | |
machty [6:29 PM] | |
@mmun with the single-main template block that you can pass in today, any other snippets of DOM that you want to override can only be approximated by passing in a bunch of additional attributes (where a separate block would have just taken care of it) (which puts an upward pressure on attr count) (edited) | |
mmun [6:29 PM] | |
If you allow more {whatever} its {whatever} soup | |
sclaxton [6:30 PM] | |
I don’t agree | |
mmun [6:30 PM] | |
Blocks, attrs etc | |
sclaxton [6:30 PM] | |
in this instance | |
[6:31] | |
components mirror html’s hierarchical structure, which is suited to make nested structures readable | |
mmun [6:32 PM] | |
@machty is the subtext that high attr count is worse than medium attr + block count? (edited) | |
machty [6:32 PM] | |
and strings model arrays of characters; should they have special data-hiding semantics to separate them from references to Number? | |
[6:33] | |
@mmun no, that's a point that validates both @sclaxton's and my push for being able to pass multiple template blocks. just saying that regardless of whether template blocks live in their own namespace or are attrs, there will still be a downward pressure on attr count | |
sclaxton [6:33 PM] | |
plz convince me that html-style hierarchically structured templates aren’t that important, then I will agree with everything | |
mmun [6:34 PM] | |
Why is that a metric being considered | |
machty [6:34 PM] | |
@mmun because it's an argument against the idea that attrs=blocks necessarily means attr soup (edited) | |
[6:34] | |
@mmun it is a pressure in the opposite direction of attr soup (edited) | |
sclaxton [6:35 PM] | |
@machty agree w that | |
mmun [6:35 PM] | |
If you design your component poorly your going to have value soup no matter what | |
[6:35] | |
Regardless of attr soup | |
sclaxton [6:35 PM] | |
but still think html-like hierarchically structured templates are a boon | |
locks [6:35 PM] | |
I don't understand ^ | |
mmun [6:35 PM] | |
The number of things you can use in your template is the same either way | |
sclaxton [6:36 PM] | |
@locks my thing? | |
locks [6:37 PM] | |
yes | |
machty [6:38 PM] | |
```{{#x-foo | |
headerTitle="..." | |
headerTagName=... | |
headerWat=... | |
... | |
}} | |
Look at me, i'm the special one who got to | |
use the default block API; watch me as i close | |
over {{foo}} {{bar}} and {{baz}}. Unfortunately | |
x-foo also renders a header and footer and those | |
have overrideable bits too, but those overridable | |
bits can only be passed in as additional attrs, | |
like `headerTitle=` `headerTagName=` `headerWat=`. | |
But if we could just pass in multiple blocks w | |
closed over scope (regardless of whether we go | |
w machty's / sclaxton's approach), so many | |
of those attrs can go away. | |
{{/x-foo}} | |
``` | |
[6:38] | |
@sclaxton you haven't responded to my experiment combining your syntax with my semantics | |
[6:39] | |
which maintains all the hierarchically structured syntax (as per your designs) (edited) | |
sclaxton [6:39 PM] | |
```{{thing}} | |
{{child}} | |
{{grand-child}} | |
{{/child}} | |
{{/thing}} | |
``` | |
[6:39] | |
^ @locks html-like hierarchically structured template (edited) | |
[6:40] | |
basically open/close tags | |
[6:40] | |
it makes hbs seem like an html-enhancement language, which I think is a valuable way to think of it | |
mmun [6:40 PM] | |
So you punt on being able to pass a dynamic amount of blocks e.g. the column case? | |
machty [6:41 PM] | |
@mmun thanks for reminding me. yes. i do. and that sucks. i keep forgetting that important use case. and it is important (edited) | |
sclaxton [6:41 PM] | |
@machty I need to think about that a little more | |
[6:41] | |
gotta bounce tho | |
mmun [6:41 PM] | |
Im 2% battery. Good chat ttyl | |
sclaxton [6:42 PM] | |
also, sorry I keep bouncing around arguments. having trouble expressing what it is about moving wholesale to template passing via attrs that bothers me | |
mmun [6:43 PM] | |
I feel like witg both named blocks and block lamdas everyone would be happy. Cant say if its too much to add tho yet (edited) | |
sclaxton [6:43 PM] | |
but I think the loss of html-like hierarchy is a good distillation of it? | |
locks [6:43 PM] | |
I don't see how it is, so I think I'm missing something | |
mmun [6:43 PM] | |
You must not like yield either then? | |
machty [6:43 PM] | |
yeah, i don't think passing in code via `<div>child nesting</div>` is more "hierarchical" / "structural" than passing multiple hierarchies in as attrs (edited) | |
[6:44] | |
certainly that is the convention and shared understanding | |
[6:44] | |
but i'd like to change that because it's not actually correct | |
sclaxton [6:49 PM] | |
How does yield break the hierarchy? | |
machty [6:49 PM] | |
yeah i didn't understand that comment either | |
mmun [6:54 PM] | |
nevermind | |
[6:54] | |
https://embercommunity.slack.com/archives/topic-forms/p1485042185003737 | |
this is a dangerous constraint in the general case | |
sclaxton | |
but I think the loss of html-like hierarchy is a good distillation of it? | |
Posted in #topic-formsJan 21st at 6:43 PM | |
[6:55] | |
it limits you from reusing a block | |
sclaxton [6:55 PM] | |
How so? | |
[6:56] | |
And @machty it basically marks hierarchy with parens for blocks rather than mustache tags | |
locks [6:57 PM] | |
you have to make a component if you want to use in a sibling "html scope" (edited) | |
sclaxton [6:58 PM] | |
Don't follow | |
mmun [6:58 PM] | |
how do you pass the same block to multiple components | |
sclaxton [7:00 PM] | |
Same way you would with attrs? | |
[7:00] | |
What case is that possible? | |
[7:01] | |
Or how does the invariant of open/close tag hierarchy limit that? | |
mmun [7:01 PM] | |
```{{let block=(|| ...)}} | |
{{my-component block=block}} | |
{{my-component block=block}} | |
``` | |
sclaxton [7:01 PM] | |
Also not sure how that's invariant lol | |
[7:02] | |
*an invariant | |
[7:02] | |
And that wouldn't be possible with current block syntax? | |
mmun [7:03 PM] | |
What do you mean current? | |
[7:03] | |
anyways, I think that what is needed is a "test suite" of use cases. | |
sclaxton [7:04 PM] | |
I think we're misunderstanding each other again lol | |
mmun [7:04 PM] | |
I personally don't feel good about strongly optimizing for the singular, named block case but I'd like to hear other people's thoughts. | |
machty [7:04 PM] | |
i understand | |
[7:04] | |
i shall try to mediate | |
[7:04] | |
because i am not tapping a mobile keyboard at dinner :slightly_smiling_face: | |
mmun [7:05 PM] | |
I think it's fine for people to say that the multiple columns case is not important to them, but the community should reach consensus | |
[7:05] | |
maybe I am over-rotating on it. (edited) | |
machty [7:05 PM] | |
agree, just that it's good to make it clear | |
[7:05] | |
i should add an example though | |
[7:05] | |
so that people will better understand what they'll miss | |
[7:05] | |
or maybe you should write it | |
mmun [7:06 PM] | |
I'm scared to comment on the rfc | |
machty [7:06 PM] | |
lol i understand that | |
mmun [7:06 PM] | |
i am too sensitive | |
[7:06] | |
:cry: | |
machty [7:06 PM] | |
last I heard, @sclaxton liked the idea of lambda block in conjunction with let | |
[7:07] | |
and that you'd just reference that lambda in multiple slots if you wanted to use it in multiple places | |
[7:07] | |
it just seems like such overlap to introduce both | |
mmun [7:07 PM] | |
yeah i hear you 100% | |
[7:08] | |
i can only imagine the amount of :confused: emojis we'd get with a dual style rfc | |
machty [7:10 PM] | |
also @sclaxton i think you're gonna have to come up with a angle-bracket centric syntax for your RFC since that's the direction things are headed | |
[7:10] | |
i'd be curious to see what that'd look like | |
mmun [7:11 PM] | |
the rust community has dealt with really hard syntax+semantics issues as well | |
[7:11] | |
specifically around higher kinded types | |
sclaxton [7:11 PM] | |
Id want to wait for the black param syntax for angle brackets to settle a bit | |
mmun [7:11 PM] | |
people have wanted them for _years_ but no one has really submitted a complete design | |
sclaxton [7:11 PM] | |
*block | |
locks [7:11 PM] | |
you can edit Slack messages | |
mmun [7:12 PM] | |
the thing I appreciate about that rust community is that people generally try to work together and understand eachother's constraints | |
[7:12] | |
I hope that happens with this RFC. (edited) | |
locks [7:12 PM] | |
@machty I don't think there should be an angle brackets syntax | |
machty [7:13 PM] | |
yeah | |
[7:13] | |
i dunno | |
[7:13] | |
as i've mentioned i really don't give 3 damns about angle bracket | |
locks [7:13 PM] | |
and that's web components territory :dash: | |
mmun [7:14 PM] | |
it makes little sense to discuss the new block stuff with respect to angle bracket components in an RFC today. I think it could be explored casually out of RFC. (edited) | |
[7:16] | |
the people who want angle bracket components should be speaking up in the RFC (and writing their own RFC! soon!!!) | |
locks [7:16 PM] | |
sure, when there's an rfc :P | |
machty [7:19 PM] | |
i think i brought up angle bracket because we're both proposing new syntaxes that don't exist in classic HTML, where the whole construct of "hierarchical" originated and that we are trying to emulate, but the slot syntax doesn't look anything like that and can't really be approximate with html (without doing the WC spec style of nesting slot definitions in the "main block") (edited) | |
locks [7:20 PM] | |
that's what I was thinking | |
machty [7:20 PM] | |
if what we're proposing can't be expressed in HTML than it's totally a matter of opinion whether one syntax looks more hierarchical than the other | |
sclaxton [7:29 PM] | |
Slot syntax delineates hierarchy with mustaches tags | |
[7:29] | |
Yours with parens | |
[7:29] | |
Mustaches tags are closer to html open/close tag hierarchy imo | |
[7:30] | |
And in your syntax all components are all self close | |
[7:30] | |
Which I guess is fien | |
[7:31] | |
But still stuff that's inside isn't actually going in between the open close tags | |
[7:31] | |
Like html | |
[7:31] | |
And slots | |
machty [7:37 PM] | |
i think we understand each other. hoping we can switch to trying to convince each other based on other tradeoffs | |
sclaxton [7:40 PM] | |
I agree, but is it not clear to you that slot stays closer to html style hierarchy structure? | |
locks [7:41 PM] | |
https://embercommunity.slack.com/archives/topic-forms/p1485044371003809 crystal clear imo | |
machty | |
i think i brought up angle bracket because we're both proposing new syntaxes that don't exist in classic HTML, where the whole construct of "hierarchical" originated and that we are trying to emulate, but the slot syntax doesn't look anything like that and can't really be approximate with html (without doing the WC spec style of nesting slot definitions in the "main block") | |
Posted in #topic-formsJan 21st at 7:19 PM | |
machty [7:41 PM] | |
i guess | |
[7:41] | |
but yeah ^^ | |
[7:41] | |
we're both in fantasy syntax land | |
[7:41] | |
i see what you're saying i just don't think it's all that compelling given other more important tradeoffs | |
locks [7:42 PM] | |
I'm on that side of the fence as well | |
sclaxton [7:46 PM] | |
I don't see the trade offs you have mapping to actual use cases tbh | |
[7:46] | |
The trade offs in your rfc are all about how attr nesting will unify the api | |
[7:48] | |
But a unified APIs usefulness is also not compelling to me on its own | |
[7:48] | |
Both solve usecases | |
[7:48] | |
That are wanted | |
[7:49] | |
Yours unifies API, slots sticks to current API conventions more closely | |
[7:49] | |
To be compelled about your syntax I'm going to need something more concrete than a unified api | |
machty [7:50 PM] | |
sounds good | |
[7:50] | |
```{{x-table items=users | |
columns=(array | |
(hash | |
name="ID" | |
template=(|data| | |
{{data.user.id}} | |
) | |
) | |
(hash | |
name="Username" | |
template=(|data| | |
{{data.user.username}} | |
) | |
) | |
(hash | |
name="Last Active" | |
template=(|data| | |
{{moment data.user.last_active}} | |
) | |
) | |
(hash | |
name="Actions" | |
template=(|data| | |
{{link-to 'Edit' 'user.edit' data.user.id}} | |
{{link-to 'View' 'user.show' data.user.id}} | |
{{link-to 'Delete' 'delete-user' data.user.id}} | |
) | |
) | |
) | |
}} | |
``` | |
[7:50] | |
changing topics, need help fleshing out some things | |
[7:50] | |
(`[]` array literal and `(asd=123)` hash literal syntax would be nice here) | |
mmun [7:51 PM] | |
yeah | |
locks [7:51 PM] | |
no commas | |
[7:51] | |
it'll trip up JS devs, but it's for the best :P | |
machty [7:51 PM] | |
here's an example of dynamic/array template blocks | |
[7:52] | |
(this could be approximated with slot syntax if we also passed in an array of column slot names) (edited) | |
[7:52] | |
but one thing that's kinda lame is `{{data.user.username}}` | |
[7:52] | |
a lameness that wouldn't be present with positional block params | |
[7:53] | |
just conceding that for yall so that i don't come off so hard-nosed | |
mmun [7:53 PM] | |
bless your soul | |
machty [7:54 PM] | |
(another thing i don't like about slot syntax is you'd probably want/need API for getting all the names of slots passed in) (edited) | |
locks [7:55 PM] | |
:thinking_face: | |
[7:55] | |
since they're not passed as attrs, it'd have to be a special hing | |
machty [7:55 PM] | |
exactly | |
[7:56] | |
there are strong parallels between my thinking and the extensible web manifesto | |
mmun [7:56 PM] | |
I can totally see a slot syntax on the invoking side for the column use case | |
[7:56] | |
but the yielding part is blurrier | |
sclaxton [7:57 PM] | |
column use case? | |
machty [7:57 PM] | |
my example above | |
mmun [7:57 PM] | |
ok i've had enough. i'm gonna write in words the use cases :stuck_out_tongue: | |
sclaxton [7:58 PM] | |
:raised_hands: | |
mmun [8:09 PM] | |
https://usecanvas.com/ember/use-cases-to-consider-for-slotsblocks/1weaFXebNLNPon5boB2RdX | |
Canvas | |
Use cases to consider for slots/blocks | |
Static Slots. Notable examples. ember-power-select has several slots that can be filled if the user provides a component to a specific attribute. Otherwise, a default implementation will be used for the slot. Dynamic Slots. Notable examples. ember-table. | |
[8:10] | |
@sclaxton can you see that? | |
locks [8:10 PM] | |
table components are kinda dreadful atm | |
mmun [8:10 PM] | |
yep | |
[8:11] | |
I can flesh that doc out some more later, but am I capturing all the high level use cases? | |
sclaxton [8:19 PM] | |
Yeep | |
[8:19] | |
Well I don't know about all | |
[8:19] | |
But the ones that I've heard about most (edited) | |
mmun [8:22 PM] | |
I don't see how the column use case can be handled without treating blocks as data. At the very least you need to be able to index into an array of blocks. (edited) | |
[8:23] | |
I welcome strawmen though :slightly_smiling_face: | |
machty [8:31 PM] | |
you could do it by also passing in an array | |
[8:31] | |
with config including slotName | |
mmun [8:32 PM] | |
oh, that's good | |
machty [8:32 PM] | |
is it? | |
[8:33] | |
what if you also want to pass a template for the header | |
mmun [8:33 PM] | |
well i don't love it (because i hate naming things) but it answers my question (edited) | |
machty [8:33 PM] | |
yeah | |
machty [8:55 PM] | |
```{{x-table items=users | |
columns=(array | |
(hash | |
headerTitle="ID" | |
cellSlotName="idTemplate" | |
) | |
(hash | |
headerTitle="Username" | |
cellSlotName="usernameTemplate" | |
) | |
(hash | |
headerSlotName="lastActiveTemplate" | |
cellSlotName="lastActiveTemplate" | |
) | |
(hash | |
headerTitle="Actions" | |
cellSlotName="actionsTemplate" | |
) | |
) | |
:idTemplate as |data|}} | |
{{data.user.id}} | |
{{:usernameTemplate as |data|}} | |
{{data.user.username}} | |
{{:lastActiveTemplate as |data|}} | |
{{moment data.user.last_active}} | |
{{:lastActiveHeaderTemplate as |data|}} | |
Last Active {{clock-emoji}} | |
{{:actionsTemplate as |data|}} | |
{{link-to 'Edit' 'user.edit' data.user.id}} | |
{{link-to 'View' 'user.show' data.user.id}} | |
{{link-to 'Delete' 'delete-user' data.user.id}} | |
{{/x-table}} | |
``` | |
(edited) | |
machty [9:26 PM] | |
most people would probably move `columns` to JS (controller/component) (edited) | |
[9:26] | |
rather than dabble with `(array)` and `(hash)` | |
[9:26] | |
which would work | |
machty [9:47 PM] | |
Added the table example to the RFC, including comparison w slot syntax | |
[9:47] | |
https://github.com/machty/rfcs/blob/nested-handlebars/text/0000-nested-handlebars-syntax.md#example-table | |
[9:47] | |
there's definitely tradeoffs | |
[9:47] | |
going into it i thought the template block attrs approach would win on all counts but that's not the case | |
[9:48] | |
(i still prefer it with my bias and all, but) slots at least seem "easier", even with some of the repetition of passing slot names around | |
mmun [10:09 PM] | |
I have thrown a :wrench: | |
machty [10:10 PM] | |
i threw it back | |
[10:10] | |
look out | |
mmun [10:15 PM] | |
Hahaha | |
[10:18] | |
I made my comment more neutral | |
mmun [10:29 PM] | |
Do you consider it a _blocker_? | |
machty [10:31 PM] | |
no idea | |
----- Yesterday January 22nd, 2017 ----- | |
locks [4:00 PM] | |
http://handlebarsjs.com/partials.html what is going on in the "dynamic partial" section | |
rwjblue [4:01 PM] | |
locks it is using a helper to get the partial name | |
[4:01] | |
`{{> (whichPartial) }}` invokes the `whichPartial` helper | |
locks [4:05 PM] | |
so `whichPartial` can't be a variable? | |
rwjblue [4:11 PM] | |
inside paren like that makes it a helper invocation | |
[4:11] | |
mmun can confirm though | |
locks [4:12 PM] | |
sorry, I meant: can't you `{{> someVariable}}` and switch the variable when you want to switch the partial | |
rwjblue [4:20 PM] | |
@locks no, I don't think so, because that is going to make a literal partial named `someVariable` | |
[4:20] | |
AFAICT | |
locks [4:21 PM] | |
huh | |
machty [10:50 PM] | |
https://github.com/emberjs/rfcs/pull/203#issuecomment-274394166 | |
[10:51] | |
@sclaxton have you already started on such a polyfill? | |
sclaxton [10:52 PM] | |
it’s essentially done | |
[10:52] | |
just covering final acceptance test cases (edited) | |
machty [10:52 PM] | |
that's awesome | |
sclaxton [10:52 PM] | |
looking forward to publishing | |
[10:53] | |
I also really want to somehow fork ember-twiddle to use the polyfill so people can play around with and share example via that interface (edited) | |
machty [10:53 PM] | |
same here | |
[10:53] | |
i forget the limitations of ember twiddle | |
sclaxton [10:53 PM] | |
no addons :disappointed: | |
machty [10:53 PM] | |
i think it might not be possible ? | |
[10:53] | |
naw twiddle lets you do addons (edited) | |
[10:54] | |
but there are some other limitations | |
sclaxton [10:54 PM] | |
not broccoli based (edited) | |
machty [10:54 PM] | |
yeah that sounds right | |
sclaxton [10:54 PM] | |
like it can’t modify the build | |
machty [10:54 PM] | |
i couldn't get Emblem to compile | |
sclaxton [10:54 PM] | |
cause there is no broccoli build | |
machty [10:54 PM] | |
yeah | |
sclaxton [10:54 PM] | |
cli is essentially implemented as an ember service | |
[10:54] | |
it’s be very easy to monkey patch my polyfill in the service tho | |
machty [10:55 PM] | |
i think it'll be fine if there's an examples repo | |
sclaxton [10:55 PM] | |
wish there was a non fork path tho | |
machty [10:55 PM] | |
and people see that it's live code and they can fork and play around with it | |
[10:55] | |
yeah | |
[10:55] | |
same | |
sclaxton [10:56 PM] | |
this is such a great use case for twiddle ugh | |
[10:57] | |
but yeah, either I’ll fork and temporarily deploy the fork under some other domain, or yeah just have an example repo | |
[10:58] | |
the idea of getting it to work via twiddle interface has incepted my brain, so tbh I’ll probably just do it, even tho it’s overkill (edited) | |
machty [10:58 PM] | |
how? | |
sclaxton [11:00 PM] | |
i think it should be pretty trivial to fork, monkey patch, deploy to aws | |
machty [11:00 PM] | |
hah | |
[11:00] | |
gotcha | |
sclaxton [11:01 PM] | |
just asked @gaurav0 about it to get his thoughts | |
machty [11:25 PM] | |
it would be extremely badass if you got that working | |
[11:27] | |
not that this is a blocker but one thing that i'm not sure there's a good solution for is ambiguous helper/property syntax | |
[11:28] | |
`{{maybehelper}}` | |
[11:28] | |
the polyfill would have to pass that in | |
[11:28] | |
eh i guess that's fine it'd still find the helper | |
sclaxton [11:33 PM] | |
hmm what do you mean by pass that in? | |
[11:35] | |
the polyfill for slots essentially just parses the named slot syntax with a forked hbs parser, transforms that to valid current hbs syntax, writes the transformed hbs back to the template broccoli tree which is then parsed by the normal template preprocessors (edited) | |
[11:36] | |
it totally sidesteps anything ember specific | |
[11:36] | |
just an hbs transform | |
machty [11:46 PM] | |
how do you transform named slots to valid hbs syntax? | |
[11:46] | |
i think our syntaxes might demand different approaches but still seems like i'm not grokking something | |
sclaxton [11:50 PM] | |
I transform it to un-named multiple yields that yield a `slotName` and a hash of block params to a block with an if/else chain that conditionally renders the corresponding named slot block based on `slotName` | |
[11:50] | |
see this example https://github.com/emberjs/rfcs/pull/72#issuecomment-219174876 | |
machty [11:51 PM] | |
yeah | |
sclaxton [11:51 PM] | |
that comment sparked the whole thing haha | |
machty [11:51 PM] | |
makes sense | |
[11:51] | |
looks like angular's first router | |
sclaxton [11:52 PM] | |
? | |
machty [11:52 PM] | |
i just remember ng-route v1 just being switch statements | |
sclaxton [11:52 PM] | |
yah basically a switch | |
[11:54] | |
the hardest part was grokking the hbs ast tbh | |
[11:55] | |
writing the transforms with the hbs ast visitors was pretty mechanical (edited) | |
[11:55] | |
actually hardest part was testing lol I take it back | |
[11:55] | |
always testing | |
machty [11:56 PM] | |
i... am very unlikely to write tests for my polyfill | |
[11:56] | |
it's going to look like the homer simpson car | |
sclaxton [11:56 PM] | |
haha fair enough | |
[11:57] | |
I have a ast fixtures file that’s like a few thousand lines long :joy: | |
----- Today January 23rd, 2017 ----- | |
machty [12:04 AM] | |
set the channel topic: Backlog manually persisted here: | |
<https://gist.github.com/machty/68afad4c03109f36d4f4cffaae3c170b> | |
machty [12:04 AM] | |
(figured it was a bit pompous to just have my rfc linked here) (edited) | |
sclaxton [12:42 AM] | |
@machty just published the repo if you wanna take a look https://github.com/sclaxton/ember-cli-named-block-slots-polyfill | |
[12:44] | |
will likely publish the addon sometime this week | |
mmun [1:36 AM] | |
it's kinda interesting that this polyfill is basically what rust does for closures (edited) | |
[1:36] | |
it converts them into anonymous structs | |
[1:41] | |
if we added named block params to machty's solution i would be willing to accept it. the `data.` is too onerous for me. they're already implemented in glimmer anyways. that still leaves the issue of component vs. yield but it is a much smaller concern because you don't have to worry about postional vs named. (edited) | |
sclaxton [1:47 AM] | |
? | |
[1:48] | |
what does `data.` refer to? | |
[1:48] | |
oh | |
[1:48] | |
I gotcha | |
[1:50] | |
but yes, `data.` feels boiler platey | |
mmun [1:53 AM] | |
the syntax in your rfc is a non-starter for me because it doesn't handle a dynamic number of blocks (edited) | |
sclaxton [1:53 AM] | |
@mmun did you get over the fact that machty’s solution doesn’t really fit into vanilla hbs semantics? | |
mmun [1:54 AM] | |
well it doesn't _not_ fit into them. we're really far ahead of handlebars in terms of composition | |
[1:55] | |
my concern is that it's a lot of syntax to add without semantics. i think we need to figure out the semantics for vanilla hbs | |
sclaxton [1:55 AM] | |
I guess it would if you added self-closing block helpers to vanilla hbs? | |
[1:55] | |
which is as much work as you would have to do for my syntax change as well | |
[1:56] | |
mb less | |
[1:56] | |
but def hear you on the dynamic slots | |
[1:56] | |
that’s why my read me says “a first pass” heh | |
[1:56] | |
been doing some thinking on the dynamic case | |
mmun [1:57 AM] | |
even if you use machty's array-of-string-names solution to pass an arbitrary number of named blocks, you still can't pass a _dynamic_ amount | |
sclaxton [1:57 AM] | |
I think I may have a solution to that | |
[1:57] | |
it’s a little wild | |
[1:57] | |
but so is everything lately lol | |
mmun [1:58 AM] | |
e.g. your table may have a variable amount of columns depending on how many fields are on your records | |
sclaxton [1:58 AM] | |
oh yeah, I don’t have a solution to that yet | |
[1:58] | |
lol | |
mmun [1:59 AM] | |
it pains me when people want to add a lot of syntax | |
sclaxton [1:59 AM] | |
it is painful | |
mmun [1:59 AM] | |
vs. adding one primitve that is reusable | |
[2:01] | |
when i say "a lot of syntax" what i meant is that there is a product of syntaxes occuring because the new piece of syntax requires a variant of many several existing syntaxes (edited) | |
[2:01] | |
namely :block-a, yield:block-a, hasBlock:block-a, etc | |
[2:01] | |
where does it end? | |
[2:01] | |
does foo-bar:block-a mean something? | |
sclaxton [2:02 AM] | |
yes haha | |
[2:02] | |
but yeah, perhaps going back to full dynamic slots is preferable | |
mmun [2:03 AM] | |
I think there is a very strong syntax argument for it. | |
[2:03] | |
There's more to it than that obviously (edited) | |
sclaxton [2:03 AM] | |
I just decided to implement this static since that was the main piece of feedback on the other RFCs | |
[2:03] | |
and it seemed like that’s where the core team was headed thought wise at the time | |
[2:04] | |
from their comments | |
mmun [2:04 AM] | |
It also pains me when people suggest content-for | |
sclaxton [2:04 AM] | |
yeah no | |
[2:04] | |
pls | |
mmun [2:04 AM] | |
It's an ok solution but doesn't really support multiple blocks well and requires a funky {{yield} to kick off the side-effects. | |
[2:04] | |
we need to document this in a single place. | |
[2:04] | |
hmm i kinda recall your rfc mentioned that | |
[2:05] | |
what are "full dynamic slots"? wanna make sure i'm on the same page | |
sclaxton [2:07 AM] | |
```{{#my-component}} | |
Good Morning! | |
{{slot "header"}} | |
Hello! | |
{{slot "footer"}} | |
How Are You? | |
{{/my-component}} | |
``` | |
[2:07] | |
with like `{{yield to="header"}}` in the component def | |
mmun [2:08 AM] | |
that requires syntax changes | |
sclaxton [2:08 AM] | |
true | |
mmun [2:09 AM] | |
hope no-one has a helper called slot either O_o | |
sclaxton [2:09 AM] | |
yeah that’s the other thing | |
[2:09] | |
you could use some sort of control character to mark a slot section instead | |
[2:10] | |
not sure about the exact syntax for that | |
[2:10] | |
but that’s the general idea of what I meant by fully dynamic | |
mmun [2:11 AM] | |
```{{#my-component}} | |
Good Morning! | |
{{*slot "header"}} | |
Hello! | |
{{*slot "footer"}} | |
How Are You? | |
{{/my-component}} | |
``` | |
[2:11] | |
at best it will look something like this | |
sclaxton [2:11 AM] | |
I mean adding syntax sucks, but if it’s the right syntax, then it I think it just has to be done | |
[2:12] | |
whether this is the right syntax is the quesiton | |
[2:12] | |
this = named slots | |
[2:12] | |
but yeah, i’m ok with appending a control character | |
mmun [2:12 AM] | |
haha, you have no choice | |
sclaxton [2:13 AM] | |
or maybe just the control character | |
[2:13] | |
unless you make “slot” itself reserved heh | |
mmun [2:13 AM] | |
I prefer the lambdas because they are flexible in obvious ways | |
[2:13] | |
you want an array of them? ok do it. | |
sclaxton [2:13 AM] | |
I mean, I think lambda and named slots are orthogonal no? | |
[2:13] | |
you can have both | |
[2:14] | |
it’s more like machty’s components + lambdas vs. slots | |
[2:14] | |
since machty’s stuff requires lambda’s bassically | |
mmun [2:14 AM] | |
you are technically correct but it is cognitive dissonance to be ok with two solutions for this problem but no to be ok with two solutions for component & yield | |
sclaxton [2:15 AM] | |
by lambdas do you mean machty’s entire rfc? | |
[2:15] | |
or just anon blocks? | |
mmun [2:15 AM] | |
generally the latter | |
[2:16] | |
but sometimes referring to machty's particular flavor | |
sclaxton [2:16 AM] | |
kk | |
mmun [2:16 AM] | |
the `data` hash is just tooooo clunky for me | |
[2:16] | |
it's as if python named args were given as a hash | |
[2:17] | |
it needs more language support (named block args) to satisfy me (edited) | |
[2:18] | |
handlebars already has a notation for it | |
[2:18] | |
`@foo` | |
sclaxton [2:18 AM] | |
ah word | |
mmun [2:18 AM] | |
that is _exactly_ the original purpose of `@foo` | |
[2:18] | |
to be a named block argument | |
[2:18] | |
kinda funny to come full circle | |
[2:19] | |
the original issue is that the binding was implicit so that you couldn't rebind it and you would get owned when nesting | |
[2:20] | |
```{{#each doctors}} | |
{{log @item.name}} | |
{{#each @item.appointments}} | |
{{log @item.time}} | |
{{! uh oh, how do you access the doctor? }} | |
{{/each}} | |
{{/each}} | |
``` | |
(edited) | |
[2:20] | |
^ handlebars 2.0, pre-block params | |
sclaxton [2:21 AM] | |
i c | |
mmun [2:22 AM] | |
```{{#each doctors as |item=doctor|}} | |
{{log doctor.name}} | |
{{#each doctor.appointments as |item=appointment|}} | |
{{log appointment.time doctor.location}} | |
{{/each}} | |
{{/each}} | |
``` | |
[2:22] | |
or maybe | |
```{{#each doctors as |@item=doctor|}} | |
{{log doctor.name}} | |
{{#each doctor.appointments as |@item=appointment|}} | |
{{log appointment.time doctor.location}} | |
{{/each}} | |
{{/each}} | |
``` | |
sclaxton [2:23 AM] | |
prefer latter | |
mmun [2:23 AM] | |
yeah | |
sclaxton [2:23 AM] | |
easier to scan | |
mmun [2:23 AM] | |
confirm | |
[2:24] | |
so that looks good in the edge case where you need to rebind | |
[2:24] | |
what do you think about | |
```{{#each doctors}} | |
{{log @item.name}} | |
{{/each}} | |
``` | |
```{{#each doctors as |@item|}} | |
{{log @item.name}} | |
{{/each}} | |
``` | |
```{{#each doctors as |@item=|}} | |
{{log @item.name}} | |
{{/each}} | |
``` | |
(edited) | |
sclaxton [2:25 AM] | |
argh | |
mmun [2:25 AM] | |
the first is just too messed up imo | |
sclaxton [2:25 AM] | |
don’t like first heh | |
mmun [2:26 AM] | |
(which is the semantics that hbs supports today) (edited) | |
sclaxton [2:27 AM] | |
also side note, but I kinda wish we could change `as` to `with` | |
[2:27] | |
so it makes for sense for non-iterator like block helpers (edited) | |
[2:28] | |
or mb just allow both | |
[2:28] | |
but probs not allow both | |
mmun [2:29 AM] | |
well | |
[2:29] | |
with lambdas... :troll: | |
sclaxton [2:30 AM] | |
tru | |
[2:30] | |
damn, I’m so close to being ok with machty’s rfc | |
mmun [2:30 AM] | |
nah don't be | |
[2:30] | |
if you believe in your idea keep pushing it :smile: | |
[2:32] | |
in jsx, its very nice that there is a `children` array generated automatically and you dont have to pass everything as props (edited) | |
sclaxton [2:32 AM] | |
right | |
mmun [2:32 AM] | |
otherwise | |
```<MyDiv><span><b></b></span></MyDiv> | |
``` | |
would be... oh god (edited) | |
sclaxton [2:33 AM] | |
don’t do it | |
mmun [2:34 AM] | |
```<MyDiv children={function() { | |
return <span children={function() { | |
return <b />; | |
}} />; | |
}} /> | |
``` | |
(edited) | |
sclaxton [2:36 AM] | |
which is kind of what we’re moving to | |
[2:36] | |
with machty’s rfc (edited) | |
mmun [2:36 AM] | |
not exactly! | |
[2:37] | |
it's somewhere in between | |
sclaxton [2:37 AM] | |
fair | |
mmun [2:37 AM] | |
```<MyDiv children={<span><b></b></span>} /> | |
``` | |
(edited) | |
[2:38] | |
its only for ember components that you would be passing by props | |
[2:39] | |
I still am torn about using parens for delimeters | |
sclaxton [2:40 AM] | |
so here’s my current thinking, slots optimize (readability wise mostly I guess but that’s a matter of taste so meh) for the case where you have information about the blocks you expect for the components, machty components + lambdas optimize for the case where you don’t have that information | |
mmun [2:40 AM] | |
I think having both slots + lambdas would be nice (edited) | |
sclaxton [2:40 AM] | |
so why not optimize for both | |
[2:41] | |
the cognitive dissonance will exist probably | |
[2:41] | |
but it’s just a question of how much would it exist | |
mmun [2:42 AM] | |
i think elixir has both named blocks and lambdas (edited) | |
sclaxton [2:42 AM] | |
like why pass in stuff as attrs when you up front know the names of the blocks you’re passing | |
[2:43] | |
I think the use case optimization would be the guide to help people through the cognitive dissonance | |
mmun [2:45 AM] | |
have you looked at elixir? | |
sclaxton [2:45 AM] | |
not really in depth | |
mmun [2:45 AM] | |
```iex> if(false, [do: :this, else: :that]) | |
:that | |
``` | |
(edited) | |
sclaxton [2:46 AM] | |
insteresting | |
mmun [2:46 AM] | |
if takes a map of do/else | |
[2:46] | |
not unlike your named blocks | |
sclaxton [2:49 AM] | |
also lambdas would curb the need for dynamic slots? | |
[2:49] | |
basically the dynamic use cases could be handled with lambdas | |
[2:49] | |
static use cases with static named slots (edited) | |
mmun [3:23 AM] | |
yep | |
[3:24] | |
add-on authors will need to pick one though | |
sclaxton [3:24 AM] | |
why not mix and match? | |
[3:24] | |
what if some of your blocks are dynamic in nature | |
mmun [3:24 AM] | |
i mean for each "slot" they will need to pick whether they will support lambda/slot/both | |
[3:25] | |
and lambdas are applicable in more cases, i.e. a more generic solution (edited) | |
[3:25] | |
so i fear for slots :stuck_out_tongue: | |
sclaxton [3:26 AM] | |
not sure I follow why they would tend to go whole sale to one | |
[3:26] | |
but yeah, there is a choice | |
[3:27] | |
it feel like having both would be nice tho | |
mmun [3:27 AM] | |
different ppl will design components differently | |
sclaxton [3:27 AM] | |
idk mb not | |
[3:27] | |
yeah i feel | |
mmun [3:28 AM] | |
i would be sad if `{{yield to=(or header 'header')}}` became a thing | |
sclaxton [3:28 AM] | |
which is why static slots are good yeah? | |
mmun [3:29 AM] | |
it's not an argument for either solution | |
sclaxton [3:29 AM] | |
or static named yields rather | |
[3:29] | |
cause it prevents logic with yields | |
mmun [3:29 AM] | |
that doesn't make a difference | |
sclaxton [3:29 AM] | |
oh, what’s undesirable about your example then? | |
mmun [3:30 AM] | |
{{#if header}} {{yield one way}} {{else}} {{yield the other way}} {{/if}} | |
sclaxton [3:30 AM] | |
I mean can you not already do that? | |
mmun [3:30 AM] | |
actually you cant | |
[3:30] | |
but that's not the point | |
sclaxton [3:30 AM] | |
wait really why can’t you? | |
mmun [3:31 AM] | |
huh | |
[3:31] | |
you can't to=dynamicThing | |
[3:31] | |
must be a string literal | |
[3:31] | |
it is treated special at compile time | |
sclaxton [3:31 AM] | |
oh ok | |
[3:31] | |
makes sense | |
mmun [3:31 AM] | |
but that's orthogonal | |
[3:31] | |
it could work in theory | |
[3:31] | |
or with the #if | |
[3:32] | |
the point is that component users will complain/bikeshed to the component authors | |
[3:32] | |
about what should be a slot vs. lambda | |
[3:32] | |
and component authors will be like "f this, i'll just support both" | |
sclaxton [3:32 AM] | |
i see | |
[3:32] | |
yeah | |
[3:36] | |
so it seems like it’s impossible to have the flexibility we desire while also maintaining the html-like hierarchy I think is important (edited) | |
[3:38] | |
the only reason I like slots is because it’s closer to maintaining that | |
[3:38] | |
while also allowing to do some things we want to do | |
[3:40] | |
being html-like in structure is part of the spirit of handlebars, what makes handlebars what it is, e.g. one of the first first sentences on the handlebars.js home page is “Handlebars templates look like regular HTML, with embedded handlebars expressions." (edited) | |
[3:41] | |
if we’re going to get rid of that, we might as well move to another templating language | |
[3:41] | |
or just fork completely from hbs | |
[3:41] | |
to like ember handlebars or something | |
[3:41] | |
ehbs | |
sclaxton [3:47 AM] | |
or mb I’m overstating because I’m conflating block helpers with components | |
[3:48] | |
since we’re not actually making hbs un-html-like structurally, we’re making components un-html-like structurally (edited) | |
sclaxton [4:07 AM] | |
but argument still stands, I wish we could keep components html-like in structure when possible, i.e. in the non-dynamic case (edited) | |
locks [5:15 AM] | |
> +Jimmy Bishop Deja vu is a direct alteration of your current timeline by STS 4D beings. /end | |
[5:16] | |
just wanted to paste this youtube comment so we realize what these discussions could have been | |
[5:16] | |
@sclaxton I'm very confused by your argument | |
sclaxton [5:24 AM] | |
@locks removing yield for components means we remove html-like nesting of block *literals* for components (edited) | |
[5:25] | |
instead nesting of block literals occurs within attrs definitions (edited) | |
[5:28] | |
it might seem like a subtle and trivial change, but it’s a pretty big break from the spirit of the current syntax and semantics of ember components which are from an invocation point of view just handlebars block helpers (edited) | |
locks [5:29 AM] | |
but… that happens already | |
sclaxton [5:29 AM] | |
it doesn't | |
[5:29] | |
block *literals* | |
[5:29] | |
that’s why I bolded literals | |
[5:29] | |
sure right now we pass in components | |
[5:30] | |
but that’s not a literal, so it doesn’t really feel like your nesting in the attrs rather than within open/close tags (edited) | |
locks [5:30 AM] | |
that sounds extremely arbitrary | |
[5:31] | |
and isn't this why people use ember-elsewhere | |
sclaxton [5:32 AM] | |
not sure what ember-elsewhere has to do with this | |
[5:32] | |
I’m just saying that nesting literals in attrs breaks the “it looks like regular html” promise of handlebars | |
[5:33] | |
cause it doesn’t look like regular html at all | |
[5:33] | |
if we want to break that description of embers version of handlebars + components, then fine | |
locks [5:33 AM] | |
nothing inside `{{}}` does | |
sclaxton [5:34 AM] | |
but as of now you don’t put html literals inside of `{{}}` | |
[5:34] | |
so there’s a clear separation | |
[5:35] | |
when you’re in `{{}}` you know you’re out of html land | |
[5:35] | |
not so in the new syntax | |
[5:38] | |
let me phrase the argument like this: right now curlies are self contained and define the boundary between “just html” and hbs syntax, they also nest like child html literal content like html does, with hierarchical open/close tags. With the new syntax machty proposes, there is no such separation between hbs syntax and html literals and there is no such html like nesting of child html literal content. | |
[5:39] | |
that’s not arbitrary | |
locks [5:39 AM] | |
did you see the inline partial/decorator link I posted the other day? | |
[5:39] | |
you still have the boundary ¯\_(ツ)_/¯ | |
sclaxton [5:40 AM] | |
explain | |
[5:40] | |
ples | |
locks [5:41 AM] | |
`{{…}}` is handlebars, `(|| …)` is html (edited) | |
sclaxton [5:41 AM] | |
you have nested boundaries sure | |
[5:41] | |
but that’s harder to grok than just a simple single curly boundary | |
[5:41] | |
imo | |
locks [5:42 AM] | |
html has no concept of lambdas | |
[5:42] | |
so yes, it would be | |
sclaxton [5:42 AM] | |
it would be what? | |
locks [5:42 AM] | |
harder to grok | |
sclaxton [5:43 AM] | |
i mean I’m saying nested boundaries are harder to grok than just a single level `{{}}` boundary, not really the lambdas themselves (edited) | |
locks [5:44 AM] | |
we only have nested boundaries because we're introducing lambdas | |
sclaxton [5:44 AM] | |
right | |
[5:44] | |
but without lambdas you can’t do machty’s thing | |
locks [5:45 AM] | |
I don't see anything in the rfc about removing yield | |
sclaxton [5:45 AM] | |
so there’s not even a discussion without lambda | |
[5:45] | |
oh well, the whole rfc was like “why not yield" | |
[5:45] | |
didn’t explicitly say remove it, but it basically did haha (edited) | |
locks [5:45 AM] | |
"why not extend the semantics of yield" | |
sclaxton [5:46 AM] | |
yield becomes pretty moot once you do the rfc | |
locks [5:46 AM] | |
@machty just didn't use as many words | |
sclaxton [5:47 AM] | |
and if we don’t remove yield, having nested literals in the attrs and in a classic nested block would be even more confusing (edited) | |
locks [5:47 AM] | |
why | |
[5:48] | |
it's the same concept | |
sclaxton [5:48 AM] | |
because then you have some blocks stuck in the open tag of your component but a special other block in between the tags? | |
[5:49] | |
how do you decide when to use the special block between the tags and when to put everything in attrs | |
locks [5:49 AM] | |
how do you decide nowadays | |
sclaxton [5:49 AM] | |
well you don’t have literal blocks in attrs haha | |
[5:49] | |
so it’s not as bad | |
locks [5:50 AM] | |
you have `(component)`, it's the same? | |
sclaxton [5:50 AM] | |
it’s not | |
[5:50] | |
you can’t put html literal content into an attr | |
[5:50] | |
so when you need to do that you put in the nested block (edited) | |
locks [5:51 AM] | |
```{{let lol (|| <h1>Hello World</h1>)}} | |
… | |
``` | |
there :P | |
[5:51] | |
look, we're not going to get anywhere | |
[5:52] | |
I'm just not getting it | |
[5:52] | |
so I'll spare you having to put up with me | |
[5:52] | |
I shall await more discussion from y'all | |
sclaxton [5:53 AM] | |
haha sorry if I’m not able to communicate clearly, or if my ideas just don’t make sense :confused: | |
[5:53] | |
both are v possible | |
locks [5:53 AM] | |
I think you're arguing a strawman, but I don't know how to articulate why | |
[5:54] | |
to me `(component)` and `(|| )` are interchangeable | |
[5:54] | |
the actual template just isn't colocated | |
sclaxton [5:54 AM] | |
ah, but to me they’re very different | |
locks [5:54 AM] | |
and it's much nicer than inline decorator/partial syntax that hbs has | |
sclaxton [5:54 AM] | |
readability wise | |
locks [5:54 AM] | |
imo inline partials in hbs already break your semantics | |
sclaxton [5:55 AM] | |
that may be | |
[5:55] | |
which sucks | |
[5:55] | |
:confused: | |
locks [5:55 AM] | |
they don't allow nesting though | |
sclaxton [5:55 AM] | |
I’d have to read up on inline partials | |
locks [5:55 AM] | |
which is the powerful bit | |
sclaxton [5:55 AM] | |
ah, yeah then that’s better I think | |
[5:56] | |
but having html in curlies currently does hurt my arguments haha | |
locks [5:57 AM] | |
http://handlebarsjs.com/partials.html | |
[5:57] | |
it's not inside the curlies, but it looks hella clunky | |
sclaxton [5:58 AM] | |
my argument is based on the idea that being able to glance at a template and get a good idea of what the output html might look like is a very good property to have for a template language | |
locks [5:58 AM] | |
(hbs doesn't have the concept of components) | |
sclaxton [5:58 AM] | |
you can argue that this is already broken by being able to pass components, sure | |
[5:59] | |
but I don’t think that’s a good argument for breaking it more | |
locks [5:59 AM] | |
by passing components, and by curly components themselves | |
[5:59] | |
`{{hello-world}}` gives you no idea what the HTML is going to look like | |
[6:00] | |
(neither would `<hello-world>` tbf) | |
sclaxton [6:00 AM] | |
right but if you nest like html, you have some idea of the structure still (edited) | |
[6:00] | |
or like the “intended” idea of the structure | |
[6:00] | |
idkkkk | |
locks [6:00 AM] | |
by that reasoning, passing lambdas is better than passing components | |
[6:00] | |
since the template is colocated | |
sclaxton [6:00 AM] | |
now i’m sounding bullshitty to myself lol | |
locks [6:01 AM] | |
fwiw, I think `yield` still has a role | |
sclaxton [6:02 AM] | |
putting html literals in an attr doesn’t communicate that it’s a logical child of the component like nesting it between the tags does imo | |
[6:03] | |
but yeah, this is getting to be a “be like html cause we should” kind of argument | |
[6:03] | |
so | |
locks [6:04 AM] | |
I need to reread the html container spec | |
[6:04] | |
it didn't make much sense the first times (edited) | |
sclaxton [6:05 AM] | |
I think it’s inevitable that some people will think will think maintaining html nesting syntax for component child content is important and some won’t and I likely won’t be able to convince anyone that doesn’t think it’s important that it is, since it’s mostly a “spirit of the syntax” bullshitty sounding argument (edited) | |
locks [6:14 AM] | |
I was reading the backlog, and now I want to do inline `each` :troll: | |
[6:16] | |
https://embercommunity.slack.com/archives/topic-forms/p1485155499004051 I don't see how this conveys nesting | |
mmun | |
```{{#my-component}} | |
Good Morning! | |
{{*slot "header"}} | |
Hello!``` | |
Show more… | |
Posted in #topic-formsToday at 2:11 AM | |
sclaxton [6:16 AM] | |
it’s content that appear between the open and close tag. slots are just “positional nesting” where you mark the position with the slot section. attrs also conveys nesting just fine, just not in a way that’s as inline with html and current handlebars (edited) | |
[6:17] | |
of the component | |
[6:17] | |
and inline each passing a lambda? lolll | |
[6:17] | |
savin those key strokes | |
locks [6:21 AM] | |
it's weird that the slots are neither block nor inline (edited) | |
sclaxton [6:22 AM] | |
it was meant to mirror | |
```{{#if something}} | |
{{! stuff }} | |
{{else if somethingElse}} | |
{{! other stuff }} | |
{{else}} | |
{{! more stuff }} | |
{{/if}} | |
``` | |
[6:23] | |
they’re just sections, not a standalone entity | |
locks [6:24 AM] | |
but | |
[6:24] | |
html | |
[6:24] | |
:D | |
sclaxton [6:24 AM] | |
but they’re in curlies so they don’t have to be heh | |
[6:25] | |
and if/else is a well understood, well used structure, so I think it works | |
locks [6:25 AM] | |
so are lambdas | |
[6:25] | |
both curlies and well understood/used | |
[6:25] | |
:D | |
sclaxton [6:25 AM] | |
I’m not arguing against lambdas I dont think | |
[6:25] | |
well yes i am essentially haha | |
[6:27] | |
I like lambdas tho | |
[6:27] | |
I just also don’t like losing the html-ness | |
[6:27] | |
so i’m torn | |
[6:27] | |
not even html-ness really | |
[6:27] | |
more like the handlebars-ness | |
[6:28] | |
I’m totally cool if we just fork the template lang tho | |
locks [6:28 AM] | |
it's not like we 1:1 it | |
[6:28] | |
now or ever | |
sclaxton [6:28 AM] | |
syntax wise we do no? | |
[6:28] | |
semantics wise we don't | |
locks [6:28 AM] | |
so it's a matter of picking your poison | |
[6:29] | |
changing semantics is a silent failure | |
sclaxton [6:29 AM] | |
or actually not sure if that’s the way to phrase it | |
locks [6:29 AM] | |
much more insidious | |
sclaxton [6:30 AM] | |
I think our semantics changes are additive (edited) | |
[6:30] | |
so it’s not like we’re changing semantics | |
locks [6:32 AM] | |
and looking at the latest changes, imo hbs forked it for us xD | |
sclaxton [6:32 AM] | |
in hbs `{{yield}}` is a helper that outputs something in ember hbs `{{yield}}` outputs the block passed into the block helper corresponding to the component `{{yield}}` is called in | |
[6:32] | |
so we’re just specifying what `{{yield}}` outputs in a special way (edited) | |
[6:34] | |
and yeah true, the decorators stuff is weird | |
locks [6:34 AM] | |
we :scissors: context switching | |
sclaxton [6:35 AM] | |
ok, off to sleep | |
[6:35] | |
feel sorry for the ppl who choose to catch up on this :joy: | |
locks [6:35 AM] | |
no sleep for topic-forms | |
sclaxton [6:36 AM] | |
when was the last time forms were discussed? | |
[6:36] | |
in the non-platonic sense (edited) | |
locks [6:37 AM] | |
who knows :D | |
locks [6:50 AM] | |
(nigh night) | |
==================================== | |
==================================== | |
machty [3:00 PM] | |
i'm getting salty about positional / named params again | |
machty [3:01 PM] | |
uploaded this image: Pasted image at 2017-01-30, 3:01 PM | |
Add Comment | |
rwjblue [3:01 PM] | |
@machty :kissing_cat: | |
machty [3:01 PM] | |
what does that even mean | |
[3:06] | |
@rwjblue @mmun i'll wait yalls cue to share w the higherups | |
[3:06] | |
w the illuminati | |
rwjblue [3:06 PM] | |
haha | |
[3:07] | |
@machty trying to finish some pretty annoying stuff ATM, I'll re-read fully this evening for sure though | |
machty [3:07 PM] | |
no worries | |
mmun [3:07 PM] | |
how many times can one man call his own rfc invalid | |
machty [3:07 PM] | |
is he a man or a god | |
rwjblue [3:09 PM] | |
lol | |
machty [3:10 PM] | |
can god submit an RFC so controversial that she is unable to approve it | |
miguelcobain [3:11 PM] | |
The omnipotence paradox. | |
machty [3:12 PM] | |
can god beat herself at an armwrestle | |
[3:12] | |
preeeetty dumb paradox | |
miguelcobain [3:12 PM] | |
I think it makes sense. | |
[3:13] | |
It basically proves that omnipotence can't exist. | |
rwjblue [3:13 PM] | |
or that our logic is flawed :wink: | |
machty [3:14 PM] | |
or omniscience | |
[3:14] | |
both | |
[3:14] | |
can't simultaneously know the future and maintain the ability to change it (edited) | |
rwjblue [3:14 PM] | |
ok everyone, please slowly step back from the religion..... | |
machty [3:14 PM] | |
can we first decide which one is best? | |
[3:14] | |
anywho | |
rwjblue [3:14 PM] | |
lol | |
[3:15] | |
Obviously, I'm the best | |
machty [3:15 PM] | |
while(stack.pop()) {} | |
rwjblue [3:15 PM] | |
haha, I read that as `stack.poop()` :stuck_out_tongue: | |
machty [3:15 PM] | |
while(stack.:poop:) {} (edited) | |
rwjblue [3:15 PM] | |
poopin' on the stacks | |
machty [3:16 PM] | |
yeah anywho named args are the shiz | |
[3:16] | |
they compose/merge better | |
[3:16] | |
lots of yield patterns involve passing a single `(hash bunch=of named=args)` | |
[3:16] | |
maybe Ember should just do the daring thing | |
[3:16] | |
and standardize on making that pattern nice? | |
rwjblue [3:17 PM] | |
firstly, I do not think it is not nice as written | |
[3:17] | |
it could however, be nicer | |
[3:17] | |
@machty you are ruminating about `(some=hash args=here)` as an alternative? | |
machty [3:18 PM] | |
yeah | |
[3:19] | |
kinda | |
rwjblue [3:19 PM] | |
hehe, ok | |
machty [3:19 PM] | |
it helps | |
rwjblue [3:19 PM] | |
one thing at a time boss | |
machty [3:19 PM] | |
more importantly is the section on forwarding blocks to inner components | |
[3:20] | |
anyway it's all in the doc | |
rwjblue [3:20 PM] | |
ya, reading | |
machty [3:20 PM] | |
i'm "salty" again because regardless of my RFC it felt like the positional/named arg problem kept coming up | |
rwjblue [3:20 PM] | |
well, the thing about salt is that it enhances flavor | |
machty [3:22 PM] | |
it also fends off rainbow table attacks (edited) | |
rwjblue [3:23 PM] | |
heheehehehehehehehehehehhee | |
[3:23] | |
@machty RE: ## Syntax Changes Must Be Upstreamed to Handlebars.js | |
[3:23] | |
I'm not sold on this as a hard constraint FWIW | |
[3:23] | |
IMO we are already planning on "breaking" this compat with `@foo` | |
[3:24] | |
(could be that I don't know what I am talking about there though) (edited) | |
machty [3:24 PM] | |
just trying to grease the wheels w the stubborn illuminati | |
[3:24] | |
"oh but did you think of..." "yes" (edited) | |
rwjblue [3:24 PM] | |
ya, I understand | |
[3:24] | |
just providing my opinions | |
[3:25] | |
RE: ## Syntax must be specified for {{curlies}} and <angle-brackets> | |
My current thought is to punt on `{{else}}` in GC... | |
machty [4:08 PM] | |
i wonder if the handlebars splat helper would be less controversial if we constrained it to only working with hashes generated from within handlebars templates | |
[4:08] | |
`{{x-foo ...=splatArgs}}` | |
[4:09] | |
if splatArgs is just a JS pojo, then when would glimmer know to update it? | |
[4:09] | |
hmm | |
[4:09] | |
i'm probably speaking nonsense | |
[4:09] | |
but if we similarly applied static constraints to the splat helper then maybe the problem would be simpler | |
[4:10] | |
if you generated a glimmer hash via `(hash a=123 b=456)` and then THAT was splatted at some point, i feel like we should be able to handle that efficiently | |
[4:10] | |
since it's not just a flattened POJO being passed at every layer (edited) | |
[4:11] | |
but just a bundled collection of named args that only needs to be flattened when when crossing the hbs/js layer | |
cowboyd [4:41 PM] | |
https://embercommunity.slack.com/archives/topic-forms/p1485807410005743 | |
machty | |
maybe Ember should just do the daring thing | |
Posted in #topic-formsToday at 3:16 PM | |
[4:41] | |
yes. | |
[4:42] | |
I haven’t been able to follow the discussion super closely over the past week, but I feel like there is a deeper issue of data passing that needs to be solved. | |
[4:42] | |
how to receive and pass both named and positional arguments with each interface and let everything else decompose into that. | |
[4:42] | |
hmm, that sounds gross | |
mmun [4:44 PM] | |
something like `{{yield @thing=thing to=someComponentFactory}}` is what's in my mind | |
which mirrors glimmer component invocation: `<some-component @thing={{thing}} />` (edited) | |
cowboyd [4:48 PM] | |
what about `{{(componentFactory 'some-component') @thing=thing}}`? | |
mmun [4:49 PM] | |
it could be, but it would need some design work | |
[4:49] | |
the point of `{{yield @thing=thing to=someComponentFactory}}` is to unify blocks and components (edited) | |
cowboyd [4:50 PM] | |
right, but couldn’t you unify blocks and components just by rendering whatever was at the head of an expression? | |
[4:50] | |
I know this is crazy talk, but what if yield wasn’t a keyword | |
mmun [4:50 PM] | |
yes, that's all good | |
[4:51] | |
but then you need a way to talk about the blocks passed in the old fashioned way (edited) | |
cowboyd [4:51 PM] | |
yeah, like supposed the block passed in got bound to an attribute called `yield` | |
[4:52] | |
couldn’t you treat `yield` as just an attribute that was a lambda? or even `else` for that matter? | |
mmun [4:52 PM] | |
yehuda (mildly) suggested something like that | |
machty [4:52 PM] | |
easy there | |
mmun [4:52 PM] | |
there's two camps: should blocks need to be in a separate "sigil namespace" or not? (edited) | |
[4:53] | |
`{{if @default=@default @inverse=@inverse}}` (edited) | |
[4:54] | |
might be nice to take elixir's lead and use `do/else` | |
[4:54] | |
unless: `{{if @do=@else @else=@do}}` | |
[4:55] | |
that is actually what elixir's if desguars down to O_o (edited) | |
cowboyd [5:00 PM] | |
And named blocks would be bound to this sigil namespace automatically? | |
```{{#if-wat condition}} | |
True | |
{{@else}} | |
False | |
{{@wat}} | |
WAT | |
{{/if-wat}} | |
``` | |
mmun [5:02 PM] | |
I'm not sure what you mean there. that syntax is very misleading | |
[5:02] | |
are those supposed to represent multiple blocks? | |
cowboyd [5:05 PM] | |
I’m trying to understand how those blocks are bound. so, inside the `if-wat`‘s template, I could say | |
```{{#if condition}} | |
{{yield to=@default}} | |
{{else}} | |
{{yield to=@else}} | |
{{/if}} | |
``` | |
[5:05] | |
or more concisely `{{if condition @do=@default @else=@else}}` | |
mmun [5:06 PM] | |
ok here is a coherent proposal, albeit extremely bikesheadable (edited) | |
cowboyd [5:06 PM] | |
haha | |
mmun [5:06 PM] | |
```{{#unless leaving}} | |
hello | |
{{else}} | |
goodbye | |
{{/unless}} | |
``` | |
is sugar for (very bikesheddable) | |
```{{#unless leaving}} | |
{{do:}}hello{{/do}} | |
{{else:}}goodbye{{/else}} | |
{{/unless}} | |
``` | |
which is implemented as | |
```{{if do=else else=do}} | |
``` | |
(edited) | |
cowboyd [5:08 PM] | |
That feels good. | |
mmun [5:09 PM] | |
Using glimmer components (obviously we would never impement unless/if like this), | |
```<ember-unless @condition={{leaving}}> | |
hello | |
{{else}} | |
??? | |
Maybe there is no way to do {{else}} in glimmer components | |
</ember-unless> | |
``` | |
is sugar for (very bikesheddable) | |
```<ember-unless @condition={{leaving}}> | |
{{do:}}hello{{/do}} | |
{{else:}}goodbye{{/else}} | |
</ember-unless> | |
``` | |
which is implemented as | |
```<ember-if @condition=@condition @do=@else @else=@do> | |
``` | |
(edited) | |
machty [5:09 PM] | |
this looks nice ^^ (edited) | |
[5:09] | |
https://embercommunity.slack.com/archives/topic-forms/p1485812997005792 | |
mmun | |
the point of `{{yield @thing=thing to=someComponentFactory}}` is to unify blocks and components | |
Posted in #topic-formsToday at 4:49 PM | |
[5:10] | |
how does it unify? | |
mmun [5:10 PM] | |
new youtube channel | |
rwjblue [5:10 PM] | |
what happened to agreeing on the constraints? :smiling_imp: :troll: | |
machty [5:10 PM] | |
a block specifies of a block param and components get attrs? | |
[5:11] | |
@rwjblue what we're doing is essential compile-time optimizing needless discussions away (very poor analogy that will distract, please disregard) (edited) | |
mmun [5:11 PM] | |
i think what i said satisfies constraints. | |
[5:11] | |
and i agree that gathering constraints is the high order bit (edited) | |
machty [5:12 PM] | |
my document is pretty much done | |
[5:12] | |
i don't think these convos will affect it | |
mmun [5:12 PM] | |
that was my impression | |
machty [5:12 PM] | |
sorry, i'm still not getting it though | |
mmun [5:13 PM] | |
yeah, sorry I didn't make it clear how it unifies on the block side | |
machty [5:13 PM] | |
so if you do `{{x-foo someComponentFactory=(component...)}}` then a layout's `{{yield @thing=thing to=someComponentFactory}}` means... | |
[5:13] | |
`{{component someComponentFactory thing=thing}}`? (edited) | |
mmun [5:14 PM] | |
yes | |
machty [5:14 PM] | |
so how would you invoke that component in a named block way? (edited) | |
mmun [5:16 PM] | |
`{{#x-foo as |@thing|}} {{log @thing}} {{/x-foo}}` | |
[5:16] | |
with `{{yield @thing=thing}}` | |
[5:17] | |
with an option to rebind to avoid lexical issues in some cases `{{#x-foo as |@thing=thing1|}} {{log thing1}} {{/x-foo}}` (edited) | |
cowboyd [5:17 PM] | |
why not `{{@do @thing=thing}}`? | |
mmun [5:17 PM] | |
(although not strictly needed with `{{let}}`) (edited) | |
[5:18] | |
lol | |
[5:18] | |
yes, I like that too but one step at a time :stuck_out_tongue: | |
machty [5:20 PM] | |
yeah @cowboyd i know what you're saying but it's more of a future enhancement | |
[5:21] | |
i'm hacking named block params into my hacks | |
alexander-alvarez [5:21 PM] | |
the bleeding edge of ember sure is a mindscrew | |
mmun [5:22 PM] | |
it is basically ruby block kwargs | |
rwjblue [5:22 PM] | |
:joy: | |
machty [5:23 PM] | |
@mmun and the @ sigil is there for parity w how args will be passed into glimmer components? | |
mmun [5:23 PM] | |
the @ sigil disturbs me | |
[5:23] | |
I don't have a good answer for it in the whole picture | |
[5:23] | |
(curly components, glimmer components and block arguments) | |
machty [5:23 PM] | |
i mentioned the other day how maybe our syntax should unify positional params and named params | |
[5:23] | |
@samselikoff responded with "yuck" | |
[5:24] | |
but this is kinda what that is | |
mmun [5:24 PM] | |
is ruby yuck :cry: | |
[5:24] | |
kwargs4life | |
machty [5:24 PM] | |
i think something like that's fine so long as (like you said) we make sure to avoid scope pollution | |
[5:24] | |
i.e. just because a component layout does `{{yield namedArg=123 ...}}`, you should be able to remap that to another name | |
mmun [5:24 PM] | |
scope pollution is a problem with ruby kwargs as well, lemme see what they do (edited) | |
machty [5:25 PM] | |
yes, in which case you just don't use the destructure syntax (edited) | |
[5:25] | |
(but yes double check me on that) | |
mmun [5:25 PM] | |
interesting | |
machty [5:25 PM] | |
then you're back to our very favorite friend `d.data.title` :+1: | |
mmun [5:26 PM] | |
the purpose of @ for glimmer components is pretty fixed. it's intended to disambiguiate Embery-data-passing from HTMLy-attribute-setting. (edited) | |
machty [5:26 PM] | |
the cat emerged to the bag, went straight to the train and drove it away from the station | |
[5:27] | |
yeah, that seems good, just wondering if it needs to be `as |@wat|` vs `|wat=|` but confirm seems like a potentially nice opportunity to unify | |
cowboyd [5:27 PM] | |
in `{{#x-foo as |@thing=thing1|}}` how do you specify a default value? | |
mmun [5:27 PM] | |
default value was not on my radar :stuck_out_tongue: | |
machty [5:27 PM] | |
`{{let wat=(or @thing 'lol')}}` | |
mmun [5:27 PM] | |
machty for da save | |
[5:28] | |
you could do something like `(default @thing 'lol')` to be like `or` but more precise about `undefined` (edited) | |
samselikoff [5:28 PM] | |
i like kwargs | |
machty [5:28 PM] | |
if we go down this path and have to decide between remapping syntax and default value syntax, remapping should win | |
cowboyd [5:29 PM] | |
I agree | |
machty [5:29 PM] | |
or maybe it doesn't and the answer in that case is to just use single "pojo"/options arg (edited) | |
mmun [5:30 PM] | |
i'm kinda ok with that as long as the pojo args are called out | |
cowboyd [5:30 PM] | |
What made me think about it was the `|wat=|` syntax you proposed, which I like, but which also has a strong precedent for a value being on the right hand side, not a symbol used for binding. (edited) | |
mmun [5:30 PM] | |
|*d| or something (edited) | |
machty [5:30 PM] | |
@cowboyd exactly | |
[5:30] | |
tis weird | |
cowboyd [5:31 PM] | |
:troll: `|wat='default' as wat1|` | |
mmun [5:31 PM] | |
{{let foo = @bar}} | |
[5:31] | |
ahah nm we have a winner | |
[5:32] | |
`... as |wat='default' as wat1|` | |
cowboyd [5:32 PM] | |
trying to think of other ways to have the cake and eat it too.... | |
[5:33] | |
`:` has precedent as rebinding in ember for properties | |
[5:33] | |
`|wat:wat1='default value'|` | |
mmun [5:33 PM] | |
I can live with that, and hope it will be needed sparingly. | |
[5:34] | |
I worry that fussing over the syntax will turn people off from the feature | |
[5:35] | |
`import * as t, { default as Foo }, { foo as bar } from 'foo-bar';` | |
[5:35] | |
you can make anything look gnarly in the worst case | |
[5:36] | |
what should the simple case look like? | |
[5:36] | |
|wat=|? | |
[5:36] | |
feels abrupt, but seems to work for ruby/python | |
[5:37] | |
should a goal be that you can copy and paste a block into a glimmer component file and have it work? | |
[5:38] | |
if so, that would suggest that we need to use |@wat=| | |
[5:38] | |
(I'm not really convinced that that should be a goal though, since blocks can close over other stuff anyways) (edited) | |
machty [5:38 PM] | |
uploaded this image: Pasted image at 2017-01-30, 5:38 PM | |
Add Comment | |
machty [5:39 PM] | |
added this Diff snippet: diff | |
diff --git a/tests/dummy/app/templates/application.hbs b/tests/dummy/app/templates/application.hbs | |
index ffcee84..362b40c 100644 | |
--- a/tests/dummy/app/templates/application.hbs | |
+++ b/tests/dummy/app/templates/application.hbs | |
@@ -23,33 +23,33 @@ | |
{{x-table | |
items=users | |
columns=(array | |
- (hash | |
+ ( | |
headerTitle="ID" | |
- cell=(|data| | |
- {{data.item.id}} | |
+ cell=(|item=| | |
+ {{item.id}} | |
) | |
) | |
- (hash | |
+ ( | |
headerTitle="Username" | |
- cell=(|data| | |
- {{data.item.username}} | |
+ cell=(|item=| | |
+ {{item.username}} | |
) | |
) | |
- (hash | |
+ ( | |
header=(|| | |
Last <strong>Active</strong> | |
{{clock-emoji tagName=''}} | |
) | |
- cell=(|data| | |
- {{moment-from-now data.item.last_active interval=1000}} | |
+ cell=(|item=| | |
+ {{moment-from-now item.last_active interval=1000}} | |
) | |
) | |
- (hash | |
+ ( | |
name="Actions" | |
- cell=(|data| | |
- {{link-to 'Edit' 'editUser' data.item.id}} | |
- {{link-to 'View' 'showUser' data.item.id}} | |
- {{link-to 'Delete' 'deleteUser' data.item.id}} | |
+ cell=(|item=| | |
+ {{link-to 'Edit' 'editUser' item.id}} | |
+ {{link-to 'View' 'showUser' item.id}} | |
+ {{link-to 'Delete' 'deleteUser' item.id}} | |
) | |
) | |
) | |
Add Comment Collapse | |
machty [5:39 PM] | |
same code as before w 1) (a=1 b=c) hash literal syntax and 2) |asd=| named args | |
cowboyd [5:40 PM] | |
I was thinking that the other day @mmun, that it would be nice if you could do that. Basically have a component just be a block with a managed lifecycle. (edited) | |
[5:40] | |
and seemlessly upgrade from one to the other | |
mmun [5:40 PM] | |
that's pretty close to how glimmer-component is implemented in glimmer today (although it's not shipped) (edited) | |
cowboyd [5:41 PM] | |
similar to the way you can have a function be a component in JSX | |
mmun [5:41 PM] | |
the "layout" of a component is a block that is invoked with named args | |
[5:41] | |
which are referenced with `@foo` | |
[5:42] | |
I just want to expose the feature syntactically in `yield` / `as | ... |` (edited) | |
machty [5:42 PM] | |
yeah | |
[5:43] | |
i agree | |
cowboyd [5:44 PM] | |
@machty that is real nice ^^ | |
machty [5:44 PM] | |
```{{#x-calendar}} | |
{{:day as |day= isToday=|}} | |
{{/x-calendar}} | |
``` | |
[5:44] | |
is nicer than the lambda syntax | |
[5:44] | |
`cell=(|item=|` | |
[5:44] | |
specifically in that w lambda syntax and named args you get equal sign stacking ^ | |
[5:44] | |
but it's not that bad | |
mmun [5:45 PM] | |
i dont disagree that slots are nicer 98% of the time | |
[5:45] | |
:stuck_out_tongue: | |
machty [5:45 PM] | |
yeah | |
mmun [5:45 PM] | |
i would feel especially good about it if they were equivalent to a block lambda (despite the feature not existing yet or ever) (edited) | |
cowboyd [5:46 PM] | |
yeah, I would think that one would desugar to the other | |
mmun [5:46 PM] | |
exactly | |
machty [5:46 PM] | |
what does that mean | |
[5:46] | |
being able to yield to attr lambda vs slot block? (edited) | |
cowboyd [5:46 PM] | |
it means that there is an equivalent form using lambdas | |
[5:46] | |
for every named block (at least the way I was thinking about it) | |
mmun [5:47 PM] | |
yeah, every named block is just setting an arg of the same name (edited) | |
cowboyd [5:47 PM] | |
```{{#x-calendar}} | |
{{:day as |day= isToday=|}} | |
{{/x-calendar}} | |
``` | |
could also be invoked as | |
```{{x-calendar @day=(|day= isToday=| ....)}} | |
``` | |
mmun [5:48 PM] | |
but you would never do that cuz its uglier (i don't strongly believe this, but just playing the part) (edited) | |
[5:48] | |
unless you were composing components and passing blocks through by reference (edited) | |
cowboyd [5:48 PM] | |
unless you were metaprogramming, in which ugly is beautiful :slightly_smiling_face: | |
machty [5:49 PM] | |
@samselikoff so what were you "yuck"ing the other day that's different from today? | |
samselikoff [5:49 PM] | |
I need to see the example | |
[5:49] | |
I forget I guess | |
machty [5:49 PM] | |
i think you heard the words "pollute scope" and vomited in your mouth | |
samselikoff [5:49 PM] | |
(I'm not as knee-deep in this as yall but maybe that's good, get someone looking at it fresh) | |
mmun [5:50 PM] | |
fwiw, this is exactly the thing yehuda proposed a couple days ago, except he didn't understand (or didn't like ? :disappointed: ) the issue i brought up about named blocks args (edited) | |
[5:50] | |
but i feel that is a very important part of the story | |
machty [5:50 PM] | |
praise the creator | |
mmun [5:50 PM] | |
if he is :-1: kwargs the whole thing kinda crumbles | |
machty [5:51 PM] | |
:+1: | |
mmun [5:51 PM] | |
maybe i will phrase it in terms of kwargs heh | |
machty [5:51 PM] | |
nice | |
[5:51] | |
maybe reference an old blog post of his | |
[5:51] | |
and his baby | |
mmun [5:51 PM] | |
lol | |
machty [5:52 PM] | |
it takes 1 part gaslighting, 2 parts incepting | |
mmun [5:52 PM] | |
you must be so tired taking care of your new baby | |
[5:53] | |
anyways, thanks for approving that rfc about kwargs | |
samselikoff [5:54 PM] | |
lol | |
mmun [5:54 PM] | |
tbh you can get really far using what I affectionately call machty's hack | |
machty [5:54 PM] | |
it's certainly good enough to try out these ideas | |
mmun [5:54 PM] | |
columns=(array 'slot-name-1' 'slot-name-2' ...) | |
machty [5:54 PM] | |
oh | |
[5:55] | |
by machty's hack you mean "what machty calls the slot-centric approach" | |
[5:55] | |
not machty's proposed syntax | |
mmun [5:55 PM] | |
yeah, i specifically i mean dynamically referencing static blocks | |
machty [5:55 PM] | |
yeah | |
[5:56] | |
it's a bit watsauce but whatevs | |
[5:56] | |
baby steps | |
mmun [5:56 PM] | |
yeah | |
machty [5:56 PM] | |
i don't have any dynamic use caes | |
[5:56] | |
(then again you don't know what you need til someone shows you) | |
mmun [5:56 PM] | |
it makes me care about the lambda case 99.99% less | |
machty [5:56 PM] | |
yeah sames | |
mmun [5:56 PM] | |
and if i were to revisit lambdas it would be for expressions first | |
[5:56] | |
rather than blocks | |
[5:57] | |
so that cowboyd can map to his dreams content | |
new messages | |
cowboyd [5:58 PM] | |
That’s really the actual use case I care about most anyhow :slightly_smiling_face: | |
FEB 3rd | |
machty [12:00 PM] | |
been reading up on elixir | |
[12:01] | |
one of the alleged shortcomings of slot syntaxes is that you can't pass an array of slots | |
[12:02] | |
hmm ok well i just jumped 10 steps ahead and answered my own dumb question | |
[12:03] | |
anywho i'll just say that keyword args in elixir is interesting | |
[12:03] | |
http://elixir-lang.org/getting-started/keywords-and-maps.html | |
[12:03] | |
they're just lists of tuples | |
[12:03] | |
merging new args over default args doesn't "overwrite" or "clobber" the old arg | |
[12:03] | |
the old arg is still in the list, but if you're looking up args by name, the newer one will show up | |
[12:04] | |
```iex(23)> new_args = [a: 5] | |
[a: 5] | |
iex(24)> default_args ++ new_args | |
[a: 1, b: 2, a: 5] | |
iex(26)> combined = new_args ++ default_args | |
[a: 5, a: 1, b: 2] | |
iex(27)> combined[:a] | |
5 | |
``` | |
[12:04] | |
trying to imagine if there's any value to bringing something like this to ember | |
[12:04] | |
`foo=(component 'x-foo' a=1 b=2 c=3)` | |
[12:04] | |
which is rendered as `{{component foo a=5}}` | |
[12:04] | |
so `x-foo` according to the classic Ember api gets args a=5 b=2 c=3 | |
[12:06] | |
but maybe it also gets some special `@@args` arg of `(array (hash a=5) (hash c=3) (hash b=2) (hash a=1))` | |
[12:06] | |
(or reverse, i dunno) | |
[12:06] | |
can't tell whether or not this would/could be a zero-cost abstraction in glimmerland | |
[12:06] | |
and whether it'd provide any benefit? | |
[12:07] | |
for a moment i was thinking it might be useful for something like | |
[12:07] | |
```{{#x-table}} | |
{{@column as |c|}} | |
{{@column as |c|}} | |
{{@column as |c|}} | |
{{@column as |c|}} | |
{{/x-table}} | |
``` | |
[12:09] | |
but then how would you express header templates? | |
[12:12] | |
```{{#x-table}} | |
{{@header as |c|}} | |
ID | |
{{@column as |c|}} | |
{{c.id}} | |
{{@header as |c|}} | |
Name | |
{{@column as |c|}} | |
{{c.first_name}} {{c.last_name}} | |
{{@header as |c|}} | |
{{@column as |c|}} | |
{{c.email}} | |
{{/x-table}} | |
``` | |
[12:15] | |
Maybe it'd even be possible to leave out a few header templates or allow for some flexibility | |
miguelcobain [12:16 PM] | |
@machty your mental diarrheas are so awesome. Please keep them coming. | |
[12:16] | |
(not trolling) | |
machty [12:17 PM] | |
it'd be up to `x-table` to decide if/how to handle uneven / missing templates | |
[12:18] | |
the idea is it'd be cool to be able to loop through all args | |
[12:20] | |
```{{#each @@args as |@name @block|}} | |
{{#if hasBlock @block}} | |
{{yield (hash lol=123) to=@block}} | |
{{/if}} | |
{{/each}} | |
``` | |
[12:23] | |
(btw if you're wondering about all the `@`s, it's seeming more and more likely that it'll be part of the block and generic glimmer attrs syntax) | |
[12:26] | |
elixir again: | |
[12:26] | |
```iex(30)> IO.inspect do | |
...(30)> else | |
...(30)> 0 | |
...(30)> else | |
...(30)> 1 | |
...(30)> else | |
...(30)> 2 | |
...(30)> else | |
...(30)> 3 | |
...(30)> else | |
...(30)> 4 | |
...(30)> else | |
...(30)> 5 | |
...(30)> end | |
[do: nil, else: 0, else: 1, else: 2, else: 3, else: 4, else: 5] | |
``` | |
(edited) | |
ryanto [1:24 PM] | |
similar to concatenated properties? example: classNames, attributeBindings, and such | |
machty [1:26 PM] | |
yeah | |
[1:26] | |
namedConcatenatedProperties | |
[1:26] | |
well, pretty different actually | |
[1:27] | |
but there's some overlap | |
ryanto [1:27 PM] | |
ha ya | |
[1:28] | |
a would be [1,5] instead of args [a, 1][a, 5] | |
ro0gr [5:31 PM] | |
joined #topic-forms | |
machty [9:27 PM] | |
for anyone who's interested, here's a snapshot of where some of the conversations w the core team have led re: slots / named blocks | |
[9:27] | |
https://gist.github.com/machty/d196ff9fb39fe8a9be88cf0176ebf9a1 | |
[9:30] | |
disclaimer: this is still rough and hardly anyone on the core team's looked at it, but still a decent amount of feedback has been accumulated | |
mmun [9:31 PM] | |
there was some issues you raised that i'm not sure if you got answers to | |
[9:31] | |
about {{foo-bar @blah=blah}} | |
machty [9:32 PM] | |
yeah | |
mmun [9:36 PM] | |
> The classic {{else}} will continue to not support block params; if you want block params use {{as @else |a b c|}}. | |
[9:37] | |
it's fine to add it as an orthogonal thing, right? | |
[9:37] | |
pretty sure yehuda was in favor as well | |
[9:40] | |
@machty une idea | |
[9:41] | |
if we let @foo=bar be syntax for rebindings, then @@allargs could possible be @=allargs | |
[9:44] | |
oh i see, the @@allargs is interesting because it enforces splatting if you use it as an argument | |
[9:45] | |
might just cause ppl to pipe it through `hash` first haha | |
[9:46] | |
man, I think the as-blockName-blockParams is such a great ret con for using "as" as the separator token (edited) | |
machty [9:48 PM] | |
ember's API is one giant retcon | |
[9:49] | |
do you agree that we can't/shouldn't do have else in angle-brackets if we have `<as ...>`? | |
mmun [9:51 PM] | |
{{else}}? | |
[9:51] | |
or sugar for <as @else> in general? i.e. <else> (edited) | |
[9:52] | |
i'm open to anything really. at this point everything feels reasonably good and just need to see side by side comparisons with multiple options & situations (edited) | |
runspired [9:57 PM] | |
@machty I am against the `<as` | |
[9:57] | |
otherwise this seems like it’s starting to shape nicely | |
[9:58] | |
(visually it just becomes too hard to tell what’s going on I think) | |
machty [10:04 PM] | |
yeah i'm on the fence | |
[10:04] | |
proper indentation (not enforced by parser) helps | |
[10:04] | |
we might just need more examples | |
[10:05] | |
@mmun i mean `<as>` lets us avoid massive changes to Handlebars | |
[10:05] | |
but `{{else}}` (within angle brackets) would require those massive changes too (edited) | |
mmun [10:06 PM] | |
yeah | |
knownasilya [10:46 PM] | |
Left a comment about @arg naming collisions in the gist | |
mmun [10:53 PM] | |
yes that's an important consideration | |
[10:53] | |
the two solutions are 1) lean on {{let}}, 2) have a rebinding syntax | |
machty [11:40 PM] | |
yeah i was assuming #2 | |
[11:41] | |
without providing an example syntax | |
----- Yesterday February 6th, 2017 ----- | |
alexander-alvarez [12:14 PM] | |
@machty are the coffeescript crowd going to get mad at the `@` in hbs not meaing `this`? | |
machty [12:16 PM] | |
it does in a way | |
[12:16] | |
the way you pass args (what i guess used to be called attrs) in glimmer is `<x-foo @title={{someValue}}>` | |
[12:16] | |
and in x-foo's layout template you'll reference it with `{{@title}}` | |
[12:17] | |
which may actually be equivalent to `{{this.title}}` (probably not, but conceptually similar) | |
runspired [12:23 PM] | |
coffeescript be damned anyway, those folks chose their miserable 3rd class life | |
----- Today February 7th, 2017 ----- | |
machty [12:25 PM] | |
```{{#yield a b c to=@thing}} | |
Here is what gets rendered if @thing isn't passed in. | |
If @thing is passed in, then it can render this block | |
with `{{super}}` | |
{{/yield}} | |
``` | |
[12:25] | |
wat? | |
[12:25] | |
Vue has a way of defining a default thing that gets rendered when you don't pass in a block | |
[12:26] | |
^^ this is a strawman API of something that could do the same | |
[12:26] | |
I'm nowhere near super :+1: on this API but wanted to flesh it out more | |
[12:27] | |
anyway one open question is: would/should the above pass block params? | |
[12:27] | |
it _seems_ weird if it could just close over the data it needs | |
[12:27] | |
BUT | |
[12:27] | |
one alternative is this block would run with nil scope | |
[12:27] | |
zero access to anything other than its block params | |
[12:28] | |
the benefit (and a big Middle Finger ™ to all other cons) of this would be that component authors would be forced to pass in all necessary data to properly override a component (edited) | |
slackbot Custom Response [12:28 PM] | |
:explicitwarning: We'd love for this to remain an awesome place for all Emberers. Helps us out by editing that message. :point_up: https://github.com/cromwellryan/embercommunity-slack-guidelines/blob/master/CodeOfConduct.md | |
machty [12:29 PM] | |
lol | |
[12:30] | |
otherwise we might run into a situation where a default block isn't actually externally overridable | |
[12:30] | |
but i think the black-holed scope is just too weird | |
[12:30] | |
people can PR if there's useful data missing | |
[12:32] | |
for context, the alternative of the above syntax is | |
```{{#if @thing}} | |
{{yield a b c to=@thing}} | |
{{else}} | |
Here is what gets rendered if @thing isn't passed in. | |
NOTE: there couldn't possibly be any concept of | |
{{super here since we haven't actually associated | |
it with `@thing` in any way | |
{{/if}} | |
``` | |
sclaxton [12:33 PM] | |
Orthogonally, yield being a block helper was also part of my idea to have yield render component factories (edited) | |
machty [12:34 PM] | |
nice | |
[12:34] | |
yeah i think it's worth thinking through | |
[12:34] | |
related consideration: one major constraint to block syntax is that it should be trivial to forward such a syntax to other components | |
sclaxton [12:35 PM] | |
Its def weird because you'd be essentially binding params to the component while also wrapping it in an anon block | |
machty [12:35 PM] | |
if you're a component that accepts `@header` `@body` `@footer` then it should be possible to pass all of those as blocks to `{{default-component @myBlock=@header/footer/body}}` | |
sclaxton [12:35 PM] | |
Word | |
machty [12:35 PM] | |
but how would you accomplish the above with the proposed syntax | |
[12:36] | |
how would you provide a default `@header` block to pass if none was passed into you? | |
[12:36] | |
block yield couples "here is a default block" with "render it here, right now" | |
sclaxton [12:38 PM] | |
Which proposed syntax? | |
machty [12:39 PM] | |
i guess any of them | |
[12:39] | |
but assuming `@`-centric | |
[12:39] | |
or even any of the ones you've proposed | |
[12:39] | |
the only way i can imagine doing it is | |
[12:40] | |
```{{let @defaultBody as |a b c|}} | |
... | |
{{/let}} | |
{{wrapper-component @wrapBlock=(or @body @defaultBody)}} | |
``` | |
[12:41] | |
and even then i'm not sure the ^ passes the Glimmer static syntax | |
[12:41] | |
still awaiting a response from wycats on those semantics | |
sclaxton [12:41 PM] | |
mmm gotcha | |
machty [12:41 PM] | |
also i'm not sure if ^ is even supported if `@defaultBody` were declared inside the block of another component | |
[12:43] | |
```{{#each things as |t|}} | |
{{let @defaultBlock as |a b c|}} | |
wat, do I close over `{{t}}` ? | |
{{/let}} | |
{{wrapper-component @wrapBlock=(or @default @defaultDefaultBlock)}} | |
{{/each}} | |
``` | |
(edited) | |
[12:43] | |
also this demonstrates that `@defaultDefault` will be awkward to talk about (edited) | |
[12:44] | |
`@default` is possibly a bad name for `{{x-foo}}the unnamed block{{/x-foo}}` (edited) | |
sclaxton [12:44 PM] | |
Yeah I've also been thinking about that | |
[12:44] | |
Being able to pass in multiple un named blocks | |
[12:44] | |
And then somehow index into them | |
[12:45] | |
Then all blocks are named | |
new messages | |
[12:45] | |
The "un-named" are just named by an index | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment