This question relates specifically to the new Ember angle bracket component syntax, but also in general to Web Components.
I am working on upgrading an Ember application that is not on the later versions of Ember, and I decided that I would use the Ember 1.13 beta so that I can take advantage of the angle brackets components already.
I have a lot of components that built html hierarchies with other elements than div, such as a table where every tbody/tr/td is a component (for let's say having a form inside a table for manipulating rows) or a list where every li is a component. I was surprised to see that <my-component> is actually generated as <my-component> in the final html, even with tagName property set. Maybe this was unsurprising to every one else, but for me it will be a much bigger change than anything else announced for Ember 2.0. I read a bunch of articles about Web Components and couldn't see any mention of this issue, so maybe it is just a fundamental misunderstanding on my part.
How do you create components (Web/Ember) that are not block level? By restructuring your html to only have block elements as components? By writing a bunch of css to change them to non-block (such as using display: table-row) elements?
The answer is that there is no answer currently. The behaviour of angle bracket components is being worked out and there is an RFC suggesting how they should behave:
https://github.com/emberjs/rfcs/blob/angle-bracket-components/active/0000-component-unification.md
Related
I've encountered an issue with ember's (app is on 2.6.0, but seems to happen in latest as well) rendering process and its compatibility with the MathJax.js library. I have an ember twiddle (linked below) that isolates the problem, but essentially it seems like MathJax's rendering of inline equations that occur in the middle of a single text node breaks ember's re-rendering, in that the single text node becomes multiple text nodes after MathJax transforms the inline equation text into its Math elements, and the 2nd text node becomes orphaned, and remains in the DOM across re-renders.
https://ember-twiddle.com/cadfb80d7c90df98353cc3d9900f2b73/1ab7f66c3c6ca4aad15bf443bbe02fbb1f79a0d4?openFiles=controllers.application.js%2C
It may just be that my integration of mathjax with ember is just not correct, so I'd love some pointers if thats the case.
I was able to fix this with a somewhat hacky workaround:
https://ember-twiddle.com/cadfb80d7c90df98353cc3d9900f2b73
The issue (as confirmed on slack by some ember core team members) is with how MathJax modifies the DOM, in that ember is not able to keep track of the extra nodes it creates, and as a result can not properly clean up after it on re-renders.
To solve this, the component which contains the mathjax content manually sets its element's innerHTML to whatever the content attribute is set to when didRender() is fired, effectively wiping out all the DOM created/modified by MathJax. MathJax's rendering process is then invoked to render any formulas in the newly rendered content.
Note that if your content does not contain any HTML, it is recommended to set element.innerText instead of element.innerHTML.
I'm wondering if their is a tutorial on how to convert an admin UI into Ember components? What are the best practices? For example, the following UI framework: http://egemem.com/theme/kode/v1.1/blank.html
Has a main navigation, two sidebar menus, a content body and a footer. What would the best approach be to converting this into components? My initial thoughts, with very little Ember experience and based on the scattering of documents I've been able to find, I get the sense that creating unique components for everything would be the best approach. By everything I mean, everything that is unique. For example, if we take the navigation bar, there would be a parent component for the navigation as a whole and then child components for the sidebar collapse/expand buttons, the search, the drop down menus, notification indicator, etc. There would also be additional parent components for the right hand sidebar, left hand sidebar, and footer.
Looking at one of the sidebars, for example the left one, could that be one component or would child components be required here as well?
The right hand sidebar is more complex with tabs. In this example, would it make sense to break this sidebar into child components for the 3 different tabs? Would you want to go as far as a unique component for different elements of the tabs themselves. For example, each notification type would be a component?
Thank you in advance for your assistance send I look forward to understanding how best to handle this type of scenario.
Cheers,
Dan
Yes, your idea makes sense. It is a good practice to create components (or handlebars) for everything that repeats several times. I would not create different components for different tabs if they are not re-used.
Do not forget to not re-invent wheel. There are a lot of available components, take a look at Ember Observer or other similar resources.
Components are great but some the things you mentioned, like sidebars, might make more sense as nested routes, depending on what's in the sidebars.
Rock 'n Roll with Ember is a fantastic book that takes you all the way through the process of building an Ember application. It's the book I always recommend to people just getting started with the framework. http://balinterdi.com/rock-and-roll-with-emberjs/
I want to use (some of) my own ember components in a nested way. Think
{{#form-helper data=model}}
{{form-field datakey="name"}}
{{form-field datakey="street}}
{{form-field datakey="city}}
{{/form-helper}}
Generalized: I've got two components that are meant to work together in a nested way. The outer one provides some environment that is consumed by the inner one. http://alexspeller.com/simple-forms-with-ember/ has this explained in some more detail and uses the inner components parentView to access the outer context. Great.
Now, ember components are meant to fill in for web components as long as they aren't ready for prime time, but from what I understand web components are meant to be encapsulated. The only way to exchange information are data binding and events.
If this is correct and ember strives to replace its own components with web components, would this solution be future proof. Can I rely on ember delivering some kind of parentView access after the switch to real web components?
If not, what would be the right, the ember way to do this? A component outside and view helpers inside? Some usage of binding and events that I am currently unaware of?
I know I've got a solution for now, but I'm developing a solution that will be in use for quite a long time, so I want to avoid anything that's essentially deprecated at the time of writing my code.
I seem to be getting more and more confounded at what appears, on the surface at least to be pretty basic architectural questions regarding building ember apps.
Which Controller type?
In the last month or so, I've seen people implement controllers through Ember.Controller, Ember.ArrayController, Ember.ObjectController, and Ember.ArrayProxy. Removing ArrayController and ArrayProxy (due to them being identical), what are common use cases between each type?
So far, i've been able to gather that:
ArrayControllers/Proxies should be used when you have n elements within the view you intend to control
ObjectControllers should be used when the view is simple enough to maintain it's state in a single object, or be a single instance of a model's object.
Controllers --- ? No idea.
What are some basic differences between the controller types? There doesn't seem to be concrete information on when to use which, and for which use case. The API docs are good at telling me the nitty gritty of each of them, but not WHEN to use each.
The relationship between a View and a Controller can be baffling
When a View is connected via a routes ConnectOutlets function call, what exactly happens between the controller and the view?
Are events tied into the view itself (which seems to be the case) and if so, where on earth do you interact with the controller singleton to perform CRUD-esq things on its properties? this.get('controllerName') doesn't seem to do the trick, and nearly each post or tutorial or code sample out there does this a different way.
Models that aren't
I realize that Ember Data looks to help solve some of the more irritating parts of dealing with data and keeping it in sync, but at a larger perspective, in the concept of "MVC", ember doesn't really seem to have a Model of any kind. It's just some object that gets subclassed from a specific thing and then tracked....somewhere? Somehow? Magical?
#trek sufficed that an Ember.Object could manage ajax'ing data and handling state on the client just fine, but if you look at something like the todomvc.com ember app, it uses a localStorage paradigm that is COMPLETELY different in implementation then everything i've looked at.
How EXACTLY should the 'Model' part of the MVC equation be done here?
Views make me want to murder children
There seems to be a significant number of ways to construct a "view" in terms of displaying markup to a user.
ContainerViews, using subviews / childviews
nested outlets
Handlebars templates + an outlet
using #each foo in controller
Injection through literals (template: Ember.Handlebars.compile('<h1>foo</h1>') etc)
With that in mind, what's the 'proper' way to build modular UI components with ember? This more than anything is a major pain point for the adoption of this framework for me.
I love the direction that Ember is going with application development on the web. The concepts seem simple, but the verbosity is that of Objective-C (which makes sense given it's lineage) but I swear to god I feel like i'm fighting the god damned framework more than i'm actually working on my application. The verbosity of the syntax and the lack of structured documentation outside of API documentation (which lets face it, 300k of javascript is a significant amount of code to throw some breakpoints down and try to debug your issues).
I realize the challenge that you guys are up against, but hopefully this at least makes you pause for a minute and think of how you could make life easier for the incoming developer who's worked with other frameworks (or hell, even worked within an MVC framework, like rails or django or backbone or angular) and say "this is how we think ember should be used".
Take some of the opinionated software design decisions and apply them toward the community. We'll do nothing but be cheerleaders for you if you do it, promise.
Please don't hurt any children. AFAIK the ember-core team are all over 18, so any ember-view-related frustration is clearly better directed towards adults. With that in mind...
Which Controller Type?
You've got the "what" right, but maybe missing the "why". Controller can be a little misleading, especially coming from rails. Think of these controller singletons as representing the state (in-memory) of your application.
Which kind of controller to use depends on what is required for that part of your application. For example, a back-of-napkin sketch for any app might have a topnav, postList, postDetails section. In ember, each is represented by one or more view/controller pairs. In this app I would expect to see ApplicationController and NavigationController extending Ember.Controler while postList would extend ArrayController and PostDetails would be an ObjectController.
You could do it all using just Ember.Controller but ObjectController and ArrayController are really useful for wrapping model data. Any non-trivial ember app will probably use all three.
The relationship between a View and a Controller
A controller's job is to provide the context in which the view will be rendered. Ideally you'd like to keep logic out of views, so a typical controller will have lots of computed properties to do things like:
transform data from the underlying model objects
sort/filter/select a list of objects
reflect application state
whats the deal with connectOutlets? This is where you should be using the requested route/context to decide which views/data should be plugged into the outlets of your application. The controller's connectOutlet method has a bunch of magic to make it easy, but maybe too much magic. What happens (afaik) when you call: parentcontroller.connectOutlet 'child' is
Ember creates an instance of ChildView
The {{outlet}} handlebars helper in parentController's view is bound to this childView instance
The childView is rendered with the router.childController singleton as it's context
where to do crud stuff?: Typically in an action on the router. This seems crazy at first. Think of ember router not like rails but as a stateManager that just happens to also handle routing. In near-future router API will change to make this more clear. Anyway, use router actions to do things like create model instances, commit/rollback transactions and trigger state change. This is easy to do if you use the handlebars {{action}} helper for links/buttons as it targets the router by default.
Views on the other hand should have logic for "reacting to browser events" - that means really low-level stuff like show/hide something on mouseover or integrate with 3rd party libraries to do effects and animations.
You might find this screencast helpful in understanding how to do CRUD-esq things:
http://blog.bigbinary.com/2012/09/06/crud-application-in-emberjs.html
Models WTF?
Agreed in Ember any object could be used as a 'Model'. I think #trek does a good job of demonstrating how one might accomplish this via Ember.Object. This works great for a simple app, and six months back maybe would've been your best bet as ember-data was really immature. I'm not clear on the history of ember's todomvc app, but for sure it was written months ago. For sure it should be updated, but meantime I'd not recommend using it to learn about current ember best-practices.
Instead, you should go with ember-data. Over the last few months it has really evolved and should be the default choice for any new, non-trivial ember app. #tomdale just gave a great presentation on this topic, I'd recommend having a look: https://speakerdeck.com/tomdale/ember-data-internals
what's the 'proper' way to build modular UI components with ember?
For building modular UI components:
ContainerViews, using subviews / childviews
Injection through literals (template: Ember.Handlebars.compile ...)
For building an individual application:
nested outlets
Handlebars templates + an outlet
using #each foo in controller
Building modular UI components is a totally different problem than building an application. Ember.View and it's subclasses were designed for this purpose. You can easily extend/combine them to compose widgets with custom behaviors and share those widgets across applications.
At least that's how i've seen it done. If they are for internal use could also reference handlebars templates instead of object literals, but if planning to distribute the object literals approach seems best.
A great real-world example of this is the ember-bootstrap project. I learned a lot about working with ember-views by reading through that project's source. http://emberjs-addons.github.com/ember-bootstrap/
TLDR
Pick controller that maps to type of data being represented
Controllers provide context for the view and remember application state
Use ember data for your models
Use subclasses of Ember.View to make components
Be nice to children
Quite often we deal with lists of things on our site. These initially get loaded with the rest of the page from the server. However, any updates received we would like to update these lists using Ember.
All of the examples I have seen so far with Ember views deal with controlling content on a page that has always been created purely by Ember. What options are there for dealing with DOM elements that already exist on the page with Ember views?
There has been some discussion around this idea here: https://github.com/emberjs/ember.js/issues/563
In the current situation two approaches come to my mind:
Replace the static rendered list with an Ember.CollectionView as soon as all list items are available to ember as data objects (e.g through ember-data)
Use plain old jQuery to append the latest updates at the beginning / end of the list
I guess it depends on how complex your list items and the updating logic is. If updates need reordering of items and your list needs complex interaction, the first approach using ember might be better suited, although there could be a "flickering" of content while the lists are replaced. The second approach is much simpler but also limited. I would only use jQuery for appending / prepending content. Still, if the lists are simple it would be overkill to even use ember in this case.