-
Notifications
You must be signed in to change notification settings - Fork 304
Blaze outline #75
Blaze outline #75
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# Blaze | ||
|
||
1. Introduction to Spacebars -- the tracker-backed handlebars like templating syntax | ||
1. Example of spacebars syntax, data context + helpers | ||
2. Data contexts and access - name lookup (`.`, `this`, `..`, `[0]`), and null values | ||
3. Helpers, arguments, options | ||
4. Inclusion of other templates + arguments, passing data contexts | ||
5. Helpers inside tags -- returning strings and objects, `checked={{isChecked}}` | ||
6. Nested helpers + sub expressions | ||
7. Block helpers (you can create them with templates, see 10. below) | ||
8. Safestrings and `{{{` | ||
9. Builtin block helpers | ||
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 commentThe 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 commentThe 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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more.
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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
10. Comments | ||
11. Strictness | ||
12. Escaping | ||
2. Creating reusable "pure" components with Blaze / best practice (a lot of this is repeating @sanjo's boilerplate) | ||
1. Validating data context fits a schema | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, what about uses models and instances of models for data contexts? This works for us very well. Then you can just do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think SS allows you to do There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. SS? And easy checking was not the point. The point is to suggest to people to maybe consider using high-level objects as data contexts. So to describe (it is a guide) a pattern where you use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simple Schema. We are going to describe that pattern (see collections article + helpers). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. 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). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
2. Always set data contexts to `{name: doc}` rather than just `doc`. Always set a d.c on an inclusion. | ||
3. Use `{{#each .. in .. }}` to achieve the above | ||
4. Use the template instance as a component -- adding a `{{instance}}` helper to access it | ||
5. Use a (named / scoped on _id if possible) reactive dict for instance state | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we know if this actually works with hot code push? I'm not sure that just adding the ID will cut it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think better then attaching reactive dict is to simply attach reactive field or computed field. Then you can do things like: onCreated: function () {
this.foo = new ReactiveField(42);
} And in the template:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Curious why you chose the name "field" for those? Rather than property, value, etc? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, no particular reason. :-) Field is something which is more used in MongoDB context, over property. Less characters to type. I didn't use value because the primary use case was with components for me. But yea, it is not necessary the best naming. ;-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So a reactive field is sugar around Yes, a reactive-dict works as advertised (exercise for the reader, update the scaffolded app to not use the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, I'd still recommend a dict as the "default" to start with (hint hint should just be a part of all template instances without any boilerplate), as:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @stubailo agree? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, I really think we should not make it be a part of template instance just so. We have too many places where people can store then stuff, into I really think that 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The advantage of having a single point to store state is that it allows the system to do things for you. Auto-migration on HCR is a big advantage that we see already here, but another is extra APIs like the equivalent of 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 scalar -- for instance a computed field or a local collection. I don't have a good answer to this yet... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
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? |
||
6. Attach functions to the template instance (in `onCreated`) to sensibly modify state | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using reactive field you get that for free. :-)
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh right, but I mean complicated state changes that shouldn't be in the event handler. Like Template.X.onCreated(function() {
this.updateFoo = (input) => {
const newValue = do * something + complicated / with * foo;
this.state.set('foo', newValue);
}
});
Template.X.events({
'click button': function(event, instance) {
instance.updateFoo(event.target.value);
}
}); There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. Exactly. That is what we even suggest in Blaze Components. That event maps should map between selectors and methods and then all event handling should be in methods. Then you can extend those methods in child classes. And then it is really cool when:
So that you can access reactive fields as you would access some other method or property on template instance. This is a really powerful pattern. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
7. Place `const template = Template.instance()` at the top of all helpers that care about state | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I'm inclined to agree. My only hesitancy would be that in all documentation ever you find on the web you'll see @stubailo what do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's not a big deal. I'd obviously prefer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we just need to be consistent across template access, event handlers and helpers. I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
8. Always scope DOM lookups with `this.$` | ||
9. Use `.js-X` in event maps | ||
10. Pass extra content to components with `Template.contentBlock`, or named template arguments | ||
11. Use the `onRendered` callback to integrate w/ 3rd party libraries | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe document wait for subscription to finish pattern I have to use regularly:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this is an unfortunate pattern, we should add it here. lol There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Talking about promises, this is one very common pattern I am using and I have not yet made a package for it. This wait for condition and stop autoruns. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am using it a lot for inter-component communication: peerlibrary/meteor-blaze-components#82 But I have not yet found a good name or API for it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good one, thanks @mitar There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lol. Circa 2012: https://github.com/tmeasday/meteor-deps-extensions#await There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. So, should I make a package only for this or what? :-) BTW, I am starting to think that this could also be combined with promises. I will wrote more into the ticket about promises. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well I think a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
1. Waiting on subscriptions w/ `autorun` pattern: https://github.com/meteor/guide/pull/75/files#r43545240 | ||
3. Writing "smart" components with Blaze | ||
1. All of section 2. | ||
2. Use `this.autorun` and `this.subscribe`, listening to `FlowRouter` and `this.state` | ||
3. Set up cursors in helpers to be passed into pure sub-components, and filtered with `cursor-utils` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps mention how cursors are better than arrays when working with Blaze There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are cursor-utils? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. @stubailo yup There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
1. Why cursors are preferred to arrays. | ||
4. Access stores directly from helpers. | ||
4. Reusing code between templates | ||
1. Prefer utilities/composition to mixins or inheritance | ||
2. How to write global helpers | ||
5. Understanding Blaze | ||
1. When does a template re-render (when its data context changes) | ||
2. When does a helper-rerun? (when its data context or reactive deps change) | ||
1. So be careful, this can happen a lot! If your helper is expensive, consider something like https://github.com/peerlibrary/meteor-computed-field | ||
3. How does an each tag re-run / decide when new data should appear? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And attributes how are they changed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mitar I'm not quite sure what you mean here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So DOM element attributes. Things like BTW, with Blaze Components there is also a nice pattern which emerged for attributes. Namely that you can have multiple sources contribute to the same dict which you then render out. Like a dict of CSS classes, and inline style, and then you render them at once out. Instead of patching them together in templates. With inheritance and mixins you can do this really well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then you can have a simple helper like:
And just call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think they behave reactively like any other helper, no? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we should maybe just explain a bit here more, and give some good-practice examples for those attribute-helpers. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
4. How do name lookups work? | ||
5. What does the build system do exactly? | ||
6. What is a view? | ||
6. Testing Blaze templates | ||
1. Rendering a template in a unit test | ||
2. Querying the DOM (general but just a pointer here) | ||
3. Triggering reactivity and waiting for re-rendering | ||
4. Simulating events w/ JQ | ||
7. Useful Blaze utilities / other approaches | ||
1. https://github.com/peerlibrary/meteor-blaze-components | ||
2. https://github.com/raix/Meteor-handlebar-helpers | ||
3. Much, much 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.
I think in this guide, we should go into detail about data context and how it relates to "Views" - we gloss over this in the intro tutorial completely.
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.
However, there is now a world in which you could use Blaze without data context entirely! We could see what that looks like.
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.
Ah, I see you have this in an explanation below.
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.
👍