-
Notifications
You must be signed in to change notification settings - Fork 305
Conversation
@@ -0,0 +1,56 @@ | |||
# Blaze | |||
|
|||
1. Introduction to Blaze -- the tracker-backed handlebars like templating syntax |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, the syntax is called spacebars, and the runtime is blaze. Like jsx and react.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Speaking of Tracker, where do we cover that in the guide??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. No, we don't explicitly. I guess it is bigger than Blaze (you should know about how it works in the React world too). Does it deserve it's own (shorter) article?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
1. `{{#if/unless}}` | ||
2. `{{#each .. in ..}}` | ||
3. `{{#let}}` | ||
1. NOTE: we need to ensure that issues around lexical scope and event handlers are resolved before we fail to even mention `{{#each}}` and `{{#with}}`. But we should attempt it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should still mention it, no matter what. People should know about them because they are often documented in old tutorials and Stack Overflow answers. Just ignoring that will make them hard to understand how to migrate to new stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well this isn't the full documentation of spacebars (or is it?).
I think in general, in the guide we mention things we think people should use. Like we aren't going to mention allow and deny really.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stubailo what do you think about this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in general, in the guide we mention things we think people should use.
Yea, but I think that with proper use they are still useful. So maybe we should document proper use, instead of not documenting it at all. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's similar to allow/deny - we should mention it in the same way perhaps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Then you can do things like:
And in the template:
But yea, it is not necessary the best naming. ;-)
ReactiveVar
? That's nice -- I can get behind it.Yes, a reactive-dict works as advertised (exercise for the reader, update the scaffolded app to not use the
Session
, it's like a million times better and embarrassing that we haven't already done this).{{instance.state.get 'counter'}}
.state
, into template instance, into data context. Too many choices then mean people will be confused where to store it, and some people will use something, other something else so things will be less interoperable.I really think that
{{instance.counter}}
is much nicer than{{instance.state.get 'counter'}}
. Moreover, it allows you to have multiple stuff attached toinstance
. Like computer field, or simply a method/function. And you can then call all in the same way, withinstance.something
. Otherwise you have some stuff instate
, some stuff in data context, some stuff as a method, some stuff as a computed field.I really think this is bad design. There is no need for this. While my other comments are just comments, here I really think strongly that the best thing is just to encourage use of template instances without any need for extra sub-namespacing into
state
.Auto-migration on HCR is a big advantage that we see already here, but another is extra APIs like the equivalent of
shouldComponentUpdate(nextProps, nextState)
. This becomes a lot trickier if things are adhoc.To your point on where people should store things, I think it's simple -- in the data if it's an argument (i.e. coming down the component heirarchy), in the state if it's state that's relevant to this component (and it's children, potentially).
Where it doesn't quite make sense is if you want to store something more complex than a serializable attribute -- for instance a computed field or a local collection. I don't have a good answer to this yet...
But that could also be made automatically in the background? It is not so hard to go over all properties of a template instance and see which are reactive fields and have some interface to serialize and deserialize and stuff like that?
{{#with}}
or{{#each}}
in favor of{{#let}}
and{{#each ... in ...}}
.each ... in
provides a good way to access data in helpers, you will confuse people: Accessing lexical scope variable from event handler meteor#5280this.data()
. But yea, you do want to access. At least in my common use case for data contexts (I use data context mostly only for this, other communication between components I do differently), which is instances of documents (in my cases instances of PeerDB models). Then you have not just documents, but also methods on documents. So you can structure code in nice way: you have document properties, methods on the model, and component methods. So some code is more suitable to be together with a model, and some to be with view. But it is pretty normal then to call into model methods from template helpers as well.In some way, logic should be in template helpers in my opinion. Putting too much of it into templates, just so that you can then pass a value to a template helper so that it does not have to access the data context is probably bad.
So what I am saying is that pure Blaze has some shortcomings but that is what we have. So we should be OK with that and explain how to use that effectively, even if it is not the best approach we would take now.
{{foo}}
insideeach ... in
and it resolves to something, they should also be able to dothis.data().foo
. Otherwise this is really confusing.Maybe a method on template instances like
lookup
could be helpful, which would do two things:So you could do
Template.instance().lookup('foo')
. So something I am contemplating here: Extend data and currentData to return only a field and limit reactivity peerlibrary/meteor-blaze-components#101resolve
could also just be a global template helper we suggest to use (same asinstance
, BTW, I have seeninstance
used more around in existing code I think).I don't see what you mean here by "logic" - I wouldn't say managing which data is available where entails logic, since it's an inherent property of the view tree.
Because my simple implementation would be something like:
But, autorun does not have access to template instance. :-( In this particular case this could be solved with:
The downside of this approach of course is that template helpers are always bound to data context, so this would rerun every time data context changes. Maybe to transition away from current Blaze, a new type of helpers could be defined? Like "methods"? Which would be the same as helpers, just that they have
this
set to the template instance and no automatic data context binding?I think it could be as simple as a per-template feature flag that disables rerunning helpers on data context change, and the rest can be done in a package.
?
What about a replacement for helpers?
this
should be bound to the template instance on which the helper is defined, not to a template instance where the template helper is invoked. For the latterTemplate.instance()
should be used.)For now, I'm updating this text to remove
{{#each}}
and{{#with}}
and making a note about the resultant issues.cursor-utils
package that allows "slicing" cursors #73instanceof
checks if you really want.instanceof
checks in a straightforward way, no?transform
to transform your document from database, and then you useinstanceof
to find it.We are going to describe that pattern (see collections article + helpers).
BTW, we should consider also something about JSON schema, a standard. Simple Schema is great, but it is not inter-operable with others. Not that we should do something about this now, but in the longer term it would be great if our publish functions/mongo collection would have JSON schema associated with it (then also EJSON would be simpler).
instance
?{{instance}}
as it's clearer and I think what most people are doing anyway.this.updateFoo = (input) => {
const newValue = do * something + complicated / with * this.foo();
this.foo(newValue);
}
onRendered(function ()
const instance = Template.instance();
this.autorun(function (computation) {
if (!instance.subscriptionsReady()) return;
computation.stop();
// Use 3rd party stuff to render now something.
});
});
onRendered(function ()
const instance = this;
this.autorun(function (computation) {
if (!instance.subscriptionsReady()) return;
computation.stop();
Tracker.nonreactive(function () {
// Use 3rd party stuff to render now something.
});
});
});
Converts an array of style classes into a class attribute. It doesn't return anything
if the array is empty (or null) so that class attribute is not unnecessarily created.
class: (styleClassesArray) ->
if styleClassesArray?.length
class: styleClassesArray.join ' '