Giter VIP home page Giter VIP logo

rfcs's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rfcs's Issues

Do we need Pub/Sub in Ember

This might turn into its own RFC, but I'm branching off this discussion from a comment on The Road to 2.0.

From @kristianmandrup

A better alternative might be simple publish/subcribe from within these lifecycle events to minimize direct coupling.

From @MiguelMadero

I'm a afraid of global pub/sub for client side applications. I feel It's often abused and it's hard to follow. In the backend, it makes a bit more sense, since it's used to communicate across domain concerns, between processes that are already isolated. Within an app, I see less need for that. I like the explicit interfaces of components, they can communicate with their consumer via actions. Also using services and manipulating "shared" models they have access to the rest of the world, extending their list of collaborators and it results in more explicit interfaces, as opposed to the loosey goosey nature of pub/sub.

Pub/sub today is certainly possible by using something like amplify for pub/sub.

From @kristianmandrup

Sometimes you just want to broadcast some action globally (within component scope) and have any child component subscribing to this broadcast act on it (perhaps namespaced broadcast like "post:expand"). Same goes the other way (broadcast bubbling up parent component hierarchy:
"comment:removed" --> higher lv component notices no more comments (shown?) and broadcasts "comments:empty") and some component in the side or navbar showing "number of comments in view", receives this notice and removes itself...

comment:removed and comments:empty I think it could be a data concern. Removing it from the array should notify all of the subscribers.
post:expand, I usually expand/collapse within the same component so there's no need for external communication. If it's done externally it seems so specific that I think only one component will care about it (only one subscriber) and quite likely one place to do it (one publisher). Are this two components already related? Is the publisher the parent of the consumer?
If this is a more broad concern, is it possible that we can do it via the router and transitions?
Could we rely on models and services to do some of this and have more explicit interfaces?

This is not the first time this topic comes up and I think it merits some analysis.

{{outlet.someProp}}

There has been some loose ideation around using outlet is a keyword that allow a dev to access the routable component above it. Some example usage of this:

{{! in the layout of an arbitrarily deeply nested component }}
{{outlet.model.name}}
{{if (some-helper outlet.someState) 'foo'}}

The use cases for this are poorly defined though. If any are discovered we should discuss them here.

{{component whitelist="this-component that-one"}}

For build-time optimizations we should specify the handling of a particular property ("whitelist" in this proposal, bikeshedding welcome) on the {{component}} which defines a list of components which can be rendered.

Constraints:

  • Must be a space-separated string.

Outcomes:

  • Will be parsed out at build time.
  • Attempting to pass a variable to the whitelist attribute will result in a build error.
  • Attempting to render a component not in the whitelist when specified throws a runtime error.
  • Having no specified whitelist attribute will function per present behaviors.

This will make it possible to do graph resolution for component code (erring on the side of too many things included). Possible to implement as an addon, worth considering as part of core to make optimizations better by default.

Enhance contextual-components & helpers

I found myself in need of a way of creating something similar to contextual components but instead of creating a component and curry arguments, I wanted to do the same with a helper.

After drafting an RFC, checking previous art of the subject and chat about it on slack I realized that the matter is a bit more complicated that I naively thought at first.

I want to push this forward on an RFC but I want to write this issue first so we can list the motivation an requirement that the RFC has to consider.

Motivation

Essentially the same motivation that anyone would have to desire contextual components:

  • Dynamically invoke a helper by its name
  • Wrap a helper with some arguments and options and pass/yield it so when finally invoked on a different context the developer only has to provide missing information or overrides.
  • Allows to hide complexity from the public API of helpers.
  • Once privately-scoped components/helpers are implemented as defined in #143, it allows to expose those private components in a controlled way.

The naive idea that wouldn't work, and why

It seemed obvious that if we have a {{component}} keyword that allows to dynamically invoke components by its name and also to wrap components and attribututes into an ComponentDefinition, the only feature we need is a symmetrical {{helper}} keyword that does
the same thing with helpers.

You can read this thread in discuss, but the basic problem with this idea is:

  • While it is easy to disambiguate when the {{component}} helper is used to invoke a component and when it's used to create a contextual component, given the "eager" nature of helpers, there is no way of know the intention of the user. Example:
{{my-component 
  closeButton=(component "x-button" onClick=(action "close"))
  formatDate=(helper "moment-format" "Do MMM [at] H:MM" locale="es-ES")}}

The closeButton attribute is clearly creating a closure component with an onClick option bundling it together in a ComponentDefinition that can later on be rendered providing extra elements.

The (helper "moment-format") part is not clear tho. The intention of the user is to invoke the moment-format helper with the given arguments or is instead creating a contextual helper and pass it to my-component?

There is no way of telling what the user wants to do with helpers using a single keyword like {{component}}. We'd need a different syntax to disambiguate.

Constraints and other relevant information for the solution

Listed here without any particular order.

  • It must disambiguate "helper/component invocation" from "helper/component wrapping".
  • Currying of arguments must work as with closure actions: Invocation of a closure helper appends arguments at the end.
  • Options are merged as with Object.assign. Options passed in invocation win over those the component/helper has closed over.
  • The distinction of components/helpers is fuzzy for some people, specially for those with react background, because it reminds a lot to functional components. Is it possible that both are going to converge with glimmer-components? If so, this feature should be designed with that in mind, and the keywords should be the same for helpers and components.
  • As an addition argument for the previous point, in the new Module Unification (#143), both helpers and components are conflated under the components collection (if that is the correct term). This reinforces my idea that the keywords for wrap/invoke components/helper should be the same.
  • Support for glimmer-components. Although the exact API has not been spec'ed yet, initial strawman seems to take ver seriously the distinction between attributes and properties. The syntax of this RFC should take that into account)
  • I don't know this first hand, but I've been told that there is some fundamental incompatibility between the way glimmer-components are going to work and the way the existing {{component}} helper works that would require a new approach anyway. I'm not sure if that fundamental problem is the one I mentioned in the previous point or there is more to the story.
  • Element Modifiers: I know little-to-nothing about them apart that they exist in @mixonic's mind. How can they affect this proposal? Can they also be wrapped/invoked?
  • Is this a feature that can be spiked into an addon? My guts say "probably not".
  • There was some conversation about making the {{component}} keyword be statically analysable. Perhaps it's not relevant for this RFC, but it worth mentioning it.

The action plan, teaching issues and such would be discussed in an eventual RFC.

Pinging people that might want to read this: @mixonic @Serabe @locks

Template Inheritance

Moving this discussion from Ember issues to here. The original issue was emberjs/ember.js#11167

I think something like this should be supported, especially with the push towards components.

I want to have a parent component with a template like:

<div>Foo</div>
<div>Bar</div>
{{yield}}

And then I would expect for child components, that extend that parent component to just be able to define a template of:

<div>Baz</div>

And have it automatically put that in the yield, so whenever I used the child component, it would show up as:

<div>Foo</div>
<div>Bar</div>
<div>Baz</div>

Call set on properties via _super()

When creating a new Ember.Object, set is called for each property inside a hash passed to create(). This works well for regular properties, but may cause unintended behavior when the passed property corresponds to a computed property.

screen shot 2016-07-07 at 14 48 01

I encountered this behavior while debugging our company's Ember application, where a setter of a computed property assumed that the initializer had run. When the object was created with the property, the setter ran before the initializer, causing a error.

A possible solution was proposed in EmberJS community slack channel to call set on properties via _super() method, which would allow doing initialization first and then setting the properties.

Breaking "bugfixes" for an eventual 3.0

These are things that are very much broken but we can't change for reasons of backwards compatibility. This list is for a very specific category of issue. These should tend toward mechanical changes.

For example, query params clobber path params inside of the params object passed to the model hook. These should be separated into different keyspaces. This is breaking because it will change how people need to access query params and it's even possible that somebody was relying upon the clobbering behavior. However, with moving toward isolated query param behavior this tremendously reduces the complexity of the problem, skirts around different behaviors with refreshModel and simply setting a controller property, and makes the entire process more easily understood.

As a second example, query strings are serialized and deserialized differently in different layers of Ember. Changing this will obviously be breaking but it must be done to solve the "refresh" problem.

When you comment on this thread please identify why your issue fits this category. The canonical list will be hoisted here. Comments will only be used to identify which things should be promoted to this top post.

  • Move query params to a separate key or separate object for params into a route's hooks.
  • emberjs/ember.js#14174

Unconfirmed as to whether they should be promoted:

New API for Component Focus Management

I'm interested in proposing that new methods be added to Ember.Component to facilitate focus management for improving the accessibility of Ember apps. I envision the following new methods:

  • focus(): Sets focus to an element immediately. Takes an optional child argument. child will default to the selector specified in a new component property called focusNode. An arbitrary selector string, DOM element, or jQuery-wrapped element can also be passed for child. If no child is passed and focusNode is missing or falsey, the component's top-level element (component.$()) will be the element that receives focus.
  • focusAfterRender(): Functions just like focus(), but uses the Run Loop to delay focusing until after the next rendering cycle. Useful for when the element to focus is not yet on the page.

I've written an initial implementation that I use in my practice Ember app to support screen reader users. It consists of the following:

Here are some examples of utilizing the new API:

The biggest outstanding question I have right now is how a parent component can trigger focus of a child component, given that parents generally do not have references to their children. In my app, I'm currently calling focusAfterRender() in the parent, but passing in the child's selector.

Before I try to take this further, I'd like to know: is this new API a good candidate for an Ember RFC and for addition to Ember core?

Allow developers to declare a "dummy" link-to

Problem

Currently, there is no simple, foolproof way to declare a "dummy" link-to, i.e. one which appears on the page, receives the active class when its route (or a child route thereof) is current, but is never invoked as a result any event being triggered.

Real-world scenario

Developers want to create dropdown menus with links to child routes. They depend on Ember to add a class when the route or one of its children is current (the default class is "active") and have styles be applied by a CSS framework such as Twitter's Bootstrap. In the case of bootstrap, this is usually done with a link-to where tagName is set to li, and a plain a element is embedded within the li. By default, clicking on the li will transition to its url, although developers simply want clicking to open a dropdown menu containing child links, allowing users to navigate to a more specific part of the app.

Proposed solution

Allow developers to set an argument indicating the link-to should never be invoked. This could be done with a parameter named (for example) neverInvoke which defaults to false and indicates whether the link-to is for display only.

In the init() method for LinkComponent, if neverInvoke is true, eventName will not be bound to the _invoke() method.

Drawbacks

This increases the API surface area of link-to, and adds some complexity to the implementation of LinkComponent. Also, the number of people needing this feature is unknown.

Alternative solutions

  1. One solution I have used successfully is to set eventName to never. This feels like a hack, and developers will have to be directed to naming the event in a way which ensures it will never be triggered. Also, while the performance hit of attaching one "dead" event listener is negligible, allowing this to proliferate throughout large apps seems irresponsible.
  2. Another approach would be for developers to subclass LinkComponent and override the init() method so it removes the event listener. But since the default event name is click, this may have unintended side-effects if the developer does not change eventName to something like never, as in the first approach.

Let Ember.debug and Ember Logger return stuff

What?

Right now, Ember.debug (and its family of logger functions) prints to console then returns nothing, e.g.:

var x = "dog";
Ember.debug(x + 3);
// DEBUG: dog3
// undefined

They should be changed so that they return whatever message passed to them, e.g.:

var result, x = "dog";
result = Ember.debug(x + 3);
// DEBUG: dog3
// result == "dog3"

Why?

Suppose we wrote some reasonably intuitive easy-to-understand code, e.g.:

function getRichQuick () {
  return moneyToDrugs( goldToMoney( leadToGold( this.findLead() ) ) );
}

During development, it's very likely some or all of the functions used will have errors, and while end users can use console breakpoints, introduce some function logThru (x) { console.log(x); return x; }, import such a function from some addon package, or even break the function apart and introduce intermediate variables to console.log, it would be far more convenient if Ember.debug could just return whatever is passed to it.

Plus this change would be super easy to implement and would be extremely unlikely to break anything.

Ember Data - DS.Errors not great for template consumption

After upgrading to Ember Data 1.13 and the new DS.InvalidError format we noticed some real problems with the DS.Errors API. The biggest issue for us is that it's cumbersome to look up an error by it's related field. For example, if the field firstName were to fail validation, I use to be able to do:

<input class="{{if user.errors.firstName 'error'}}" value={{user.firstName}}></input>
{{#if user.errors.firstName}}
  <div class="alert alert-danger" role="alert">
    {{user.errors.firstName}}
  </div>
{{/if}}

This allows each form input element to individually indicated if it's value is invalid and show the related error near by. For example:

screen shot 2016-01-08 at 1 26 53 pm

This shouldn't really be all that earth shattering right? A lot of apps do this. I think even bootstrap has or had this UI paradigm at some point.


The new DS.Errors API creates several more hops in the lookup process. Now instead of user.errors.firstName I have to look things up via user.errors.firstName.firstObject.message.

So this:

<input class="{{if user.errors.firstName 'error'}}" value={{user.firstName}}></input>
{{#if user.errors.firstName}}
  <div class="alert alert-danger" role="alert">
    {{user.errors.firstName}}
  </div>
{{/if}}

becomes:

<input class="{{if user.errors.firstName.firstObject.message 'error'}}" value={{user.firstName}}></input>
{{#if user.errors.firstName.firstObject.message }}
  <div class="alert alert-danger" role="alert">
    {{user.errors.firstName.firstObject.message }}
  </div>
{{/if}}

There has to be some better solution here right? What is the real world use case for having the errors even be an array? The docs show show iterating the list of errors for a single field, but I don't really understand why this would be the case.

Number parsing input for `{{input type="number"}}`

Currently the ember {{input}} has a very confusing behaviour when used with type="number" and an ember-data model attribute with attr('number').

At the moment the {{input}} treats all inputs as strings which means it usually should not directly used with an ember-data number. If you do so this will result often in dirty values that are not actually dirty but the type has changed from number to string.

I would suggest to extend the {{input}} helper with a type="number" that would change this behaviour and cast all inputs to numbers and could directly used withember-date`.

Dynamic angle bracket components

The purpose of this issue is to start a discussion around dynamic invocation of angle bracket components. First I'll recap component invocations with curly syntax. Currently we support a couple curly component invocation styles:

{{#my-component ...}} ... {{/my-component}}
{{#component componentName ...}} ... {{/component}}

Each style comes in two flavors: block and inline (aka no block). Block:

{{#my-component ...}}
  Hello, world!
{{/my-component}}

and inline:

{{my-component ...}}

In a separate RFC (#64) a contextual invocation has been proposed:

{{#some.path ...}} ... {{/some.path}}

this is intended to be used with block params. Here's an example of how you'd use this invocation style with a form building component.

{{#form-for model=post as |form|}}
  {{form.input 'title'}}
  {{form.input 'body'}}
  {{form.submit}}
{{/form-for}}

In this example the form.input component is connected to the form-for component and can see the model that was passed in. This lets the input have extra features, like providing validations on the length of the title field and making the submit button automatically call model.save().


Now let's turn back to the angle bracket case. The case of static component names is clear. The block flavor

{{#my-component ...}} ... {{/my-component}}

will be expressed by

<my-component ...> ... </my-component>

and the inline flavor

{{my-component ...}}

will be expressed by

<my-component ... />

Note that in the inline case we are giving additional semantics to self-closing tags that what is specified by the HTML spec, however we feel there are no downsides to this.

So this leaves the analogs for

{{#component componentName ...}} ... {{/component}}
and
{{#some.path ...}} ... {{/some.path}}

up in the air. Here are my thoughts on the suggestions I have seen so far:

<some.path ... > ... </some.path>

This seems like a non-starter to me because there's no immediate indication that something dynamic is happening.

<{{some.path}} ... > ... </{{some.path}}>

This fixes the problem above but it's not very elegant, especially with needing to repeat the curly. It also seems inevitable that someone will type <{{/some.path}}> for the closing path.

<{{some.path}} ... > ... </>

The closing tag doesn't really matter, so maybe we can omit it? I'm not really a fan. Even the syntax highlighter doesn't like it :P

<{{some.path}} ... > ... </component>

Maybe we can use as a generic closing tag for this case? I kind of like this idea. Lastly,

<ember-component is={{some.path}} ... > ... </ember-component>

This solution feels the most correct since it sticks to the custom elements spec, but it is unfortunately verbose. I don't see myself enjoying typing <ember-component is={{form.input}} />.

Add {{array ...}} helper

It seems it would be a perfect companion to the {{hash ...}} helper:

{{hash
  name="parent"
  children=(array
    (hash
      name="child1"
    )
    (hash
      name="child2"
    )
  )
}}

It would probably get the most use in component integration tests, but could be useful in normal templates as well. Taken from here.

Improved semantics around model hook reloading

I've recently run into some frustrations with the way model hooks are called as it relates to forcing the reload of a model. The conversation originated in emberjs/data#3704 with me thinking there was a problem with the model not calling reload despite the reload: true option being passed into findRecord in the route's model hook.

Basically, I had the query in my model hook set to call reload, but because I was passing in the entire model to the link-to helper (rather than an id) the model hook never fired, therefore never calling reload on the passed-in model.

There's also not a lot of clarity around the timing of model loading in the route. It's hard to tell from a particular whether the route will wait for the model, initialize and load the model in the background, or some other behavior. I'm super excited about the new Ember Data background reloading and caching functionality, but it seems to be more well documented in the guides, perhaps.

I think there are several things that could be done to improve this from API changes to better docs. Just curious if anyone else has experienced similar issues, and what feedback they might have on how to make this less confusing (I'm a "veteran" Ember programmer, but could imagine this being especially painful to some newcomers if they don't understand all the semantics of the link-to helper and route-level events).

Some thoughts:

  • An explicit modelHook attribute on link-to helpers, to specify that, regardless of whether an id or model is passed to a dynamic url segment, the model is refreshed
  • Better documentation - the Guides only briefly mention passing the model vs. the id in link-to helpers, here and here.

I realize that these pain points can all be avoided with "good programming practices," but there is a lot of subtlety in the API here that could be made more declarative to improve the dev experience.

Thanks and looking forward to input from others! Happy to help out where I can.

Decoration

Ember has used decorators for a long time. Both in the form of ObjectController, used either along with the itemController property in {{#each}} helpers in templates or on ArrayController, and with the public ObjectProxy class.

I think the move from controllers to components is a good one! But I also find the decoration pattern useful (it exist in many frameworks, not only Ember) for some things. Maybe not for a simple TODO-app, but certainly for more advanced client applications.

Most of this can be implemented using other primitives, but parts of it would benefit from better framework support.

One is unwrapping of decorators in the action controller, which already exist for ObjectController[1].

A possible solution is to introduce a lightweight object, Ember.Decorator with a duck typing property such as isDecoratorFactory: true used to trigger unwrapping in the action helper. Unwrapping would simply be a function called e.g. unwrap, and it would be up to the decorator to unwrap itself.

If it was possible to 'sub-class' the action helper (basically get a chance to act on action helper invocations) adding decorator-unwrapping would be easy. It would also allow for other things, for example logging of all action calls.


[1] https://github.com/emberjs/ember.js/blob/4200641b9142/packages/ember-views/lib/streams/utils.js#L40

Allow components to define helpers

I might be missing something but this seems like it would be useful.

some-component.js

import Ember from 'ember';

var SomeComponent = Ember.Component.extend({
  helpers: {
    atify: function (some_string) {
      return some_string.replace('a', '@');
    }
  }
});

export default SomeComponent;

some-component.hbs

<div>
  {{ atify 'Crazy' }}
</div>

Add waitFor(selector) test helper

Referred here.

A waitFor helper would be useful for components that wrap jQuery plugins that take a while to generate their html. The problem is expanded here. It could convert this:

let done = assert.async();

click('.button-to-show-component');

setTimeout(() => {
  andThen(function() {
    assert.strictEqual(find('.jquery-stuff').length, 1);
    done();
  });
}, 500);

to this:

click('.button-to-show-component');

waitFor('.jquery-stuff');

andThen(function() {
  assert.strictEqual(find('.jquery-stuff').length, 1);
});

It would have the same basic signature as the find helper. A basic implementation is here, and it in action is here.

Add measure hook

This is a migration of emberjs/ember.js#11506 to this repo. Consult that issue for the full discussion.

Quoting @krisselden:

Add a measure hook that corresponds to didRender that silences deprecation notice for scheduling a revalidation during render.

Currently if you cause a revalidation of render during render you get a deprecation during rendering implying that support for this will eventually go away. There still exists a use case for this, where you need to render something different based on measurements of what has been rendered so far.

An example would be if you increase the height and wanted to add an additional subtree like list-view.

cc @krisselden @stefanpenner @mixonic @eccegordo

Provided attributes are not installed on a component's attrs hash as of 1.10, in contradiction to "The Road to Ember 2.0 RFC"

The text of The Road to Ember 2.0 RFC states:

In Ember 1.10, we will begin installing provided attributes in the component's attrs hash. If a provided attribute is accessed directly on the component, a deprecation warning will be issued.

In applications, you should update your component JavaScript and templates to access provided attributes via the component's attrs property.

As far as I can tell, this is incorrect-- but please correct me if I'm wrong. I tested the behavior with Ember 1.12.0 and 1.13.3, and found that:

  • this.attrs is undefined in Components as of 1.12.0
  • Attributes are available on this.attrs as specified when using 1.13.3

So it looks like attributes did not start being installed on the component attrs hash until 1.13... if this is the case, the RFC should be updated. Thanks!

[Feature request] Whitelisting which components can render within a block component

It looks like the framework doesn't support a default way of whitelisting which components can render within its yield.

{{#parent-component 
  as |first-child second-child|
}}
  {{first-child}}
  {{second-child}}
  Hello World.
{{/parent-component}}

The requirement is to be able to render {{first-child}} and {{second-child}} because they're components supplied by the parent-component but not render "hello world." or any other component/data for that matter.

A workaround is today's possible with ember-wormhole where the parent-component can have the following template:

// parent-component
<div id="first-child">
</div>
<div id="second-child">
</div>
<div style="display:none;">
  {{yield}}
</div>

And the first-child:

// first-child
{{ember-wormhole to="first-child"}}
  ...
{{/ember-wormhole}}

While it does achieve the required requirement I think it's important for a framework that offers composability to be able to handle.

Because react requires you to define the template within the render hook you're able to do it quite easily:

render() {
  return (
   <div>
     {this.props.children.filter(child => {
        return child instaceof FirstChild || child instanceof SecondChild;
     })
   </div>
  );
}

Maybe there's a way to do it which I wasn't able to find on StackOverflow nor ember set of documentation.

(originally raised emberjs/ember.js#12968)

Optional closure actions

Short version

Closure actions break if you give them an undefined value, making it impossible to have optional actions:

{{x-foo on-bar=(action attrs.not-passed baz)}}

Long Version

Consider a hypothetical image component which sends an action when it's loaded:

{{x-image image=image on-load=(action "imageLoaded")}}

Now consider an image-list component which displays a list of images:

{{#each attrs.images as |image|}}
  {{x-image image=image on-load=(action "imageLoaded" image)}}
{{/each}}

So far so good, now this component wants to just pass the loaded event up to its parent component.
Nice and easy to do with closure actions:

{{#each attrs.images as |image|}}
  {{x-image image=image on-load=(action attrs.on-image-loaded image)}}
{{/each}}

This is called as so:

{{x-image-list images=images on-image-loaded=(action "imageLoaded")}}

But we don't want to require having on-image-loaded being passed in, this now breaks:

{{x-image-list images=images}}

I know, we'll make the action optional:

{{#each attrs.images as |image|}}
  {{x-image image=image on-load=(if attrs.on-image-loaded (action attrs.on-image-loaded image))}}
{{/each}}

No dice, (if) isn't lazily evaluated, so the (action) helper gets called with undefined regardless.

Now we're stuck, we can't use closure actions anymore and have to go back to using (action "imageLoaded") and sendAction which is happy if the action isn't wired up.

Possible Solutions

In order of personal preference:

1. Make (if) lazily evaluate

Currently the (if) helper executes both branches before testing (as helpers receive values and not streams), regardless of whether the predicate is interpreted as true or false.

If this instead lazily evaluated then it would be safe to use the action keyword inside an if as the action keyword would only be called if valid:

{{x-image on-load=(if attrs.on-image-loaded (action attrs.on-image-loaded image))}}

2. Add optional=true flag to action keyword

{{x-image on-load=(action attrs.on-image-loaded image optional=true)}}

This would disable the checks in the action keyword.

I personally prefer this to 3. because it doesn't require an entirely new keyword but still makes it clear what's going on.

3. Add (optional-action) helper/keyword

{{x-image on-load=(optional-action attrs.on-image-loaded image)}}

This simply guards against undefined actions before passing along to the action keyword, but is an entirely new helper/keyword just for a guard clause

Should Ember.isEmpty({}) be true?

It seems counter-intuitive that Ember.isEmpty({}) returns false. Should it return true instead?

One theoretical hurdle I ran into while writing up the change locally was justifying that the methods which depend on isEmpty should also change. Those methods are isBlank and isPresent.

isBlank is fairly reasonable to justify: an empty object is also blank. Pretty straight-forward.

isPresent is not as easy. If Ember.isEmpty({}) returns true, then Ember.isPresent({}) returns false. This means an empty object is "not present". This seems a little strange at first. I discussed this with a colleague, and we settled on this rational:

An array is an object.
An empty array is both blank and "not present".
Therefore, an empty object is also blank and "not present".

Would you agree?

Shipping a "globals free" build of Ember for the browser

Let's explore what it would take for us to be able to ship a build of Ember that doesn't write out the Ember & Em globals. This would be beneficial for users trying to use Ember modularly within another web application where global pollution is considered a bad practice and in cases where an existing application may be embedding widgets that use different versions of Ember.

We're also using the EmberENV global to provide configuration flags from apps. It'd be nice to add another mechanism to configure Ember. Related issue in Ember-CLI: ember-cli/ember-cli#6351

Handlebars helper or component that yields inside a specified outlet anywhere in the hierarchy

My use case is as follows:

I have a dialogue that will manipulate passed in data which I want to make into a component. The dialogue would be a triggered by a button, which would open the dialogue in a "modal" outlet which lives at the application level, and is used all over the application when a modal/popup is desired.

I would like the button and dialogue to belong to the same component so everything can be self contained and I don't have to do things like create a special action on the route every time I want to use the dialogue/button combo. This way, I can just insert the component into the template where I want the button to appear, pass in the data and not have to do anything outside of the component.

I implemented a jsbin kind of hacking my way through what I wanted:

http://emberjs.jsbin.com/wavepo/6/edit?html,js,output

I also mentioned this to @wycats and @rwjblue in IRC where content_for from Rails was brought up, as well as a helper/component that could be placed into a component (or view) template in order to yield some content into a target outlet:

{{#fill-outlet "someOutsideOutlet"}}stuff in the current context{{/fill-outlet}}

were I to use the above implementation, I would do something like this in my component's template:

<button {{action "toggleShowModal"}}>Click Me</button>
{{#if showModal}}
  {{#fill-outlet "modal"}}<div>...my dialogue here</div>{{/fill-outlet}}
{{/if}}

Reduce application file size by introducing wrappers for JS Document/Element functions

I'd like to propose a potential improvement in the direction of performance/optimization and get some comments from the community. I understand this is the right repo for this kind of thing.

I work on a production Ember App. We're using up-to-date versions of the core stuff (Ember 2.6.0, Ember Data 2.6.1, jQuery 2.2.3, Ember CLI 2.6.1). The app uses a fair few components (not unusual I imagine).

The other day I happened to be perusing through the minified JS for our app's production build. I noticed that, as a result of Ember's delicious dynamic rendering of components, there were quite a few calls to JS functions in the source like the following:

  • Element.setAttribute
  • Document.createDocumentFragment
  • Document.createElement
  • Document.createComment
  • Document.createTextNode
  • Node.appendChild

The minification process can't reduce the names of these functions of course, so they really stand out when surrounded by e.g. minified variable names in the production build.

Now I'm not a JS expert, but I started wondering if, in the interest of reducing the JS download footprint, it would be possible to define wrapper functions for these functions. I'm thinking in the loose direction of defining something like Ember.sa=function(element, name, value){element.setAttribute(name,value);}.

To get a very rough feeling for its impact, I did a basic find/replace of the function names above with two-or-three letter abbreviated versions. The size of our minified script reduced by over 15%. With gzip compression this difference dropped to just over 5% (arguably still a worthwhile saving if the implementation effort is minimal). Of course the n=1 sample of our app is not exactly representative of the effect such a change would have on all Ember apps though.

Making such a change might also raise other questions, like: would the additional function call in each case introduce a significant performance overhead?

Before anybody wastes time focusing on the details, I just wanted to throw the idea out there and see if anyone else sees any merit in it (or show-stopping reasons not for doing this kind of thing).

Make Ember.ObjectProxy and Ember.ArrayProxy Public (not private)

Ember.ObjectProxy and Ember.ArrayProxy are great to use in combination with Ember.PromiseProxyMixin like Ember Data uses them. However ObjectProxy and ArrayProxy are marked Private API.

It would be great for addon developers and app developers alike to be able to use ObjectProxy and ArrayProxy combined with Ember.PromiseProxyMixin to compose attributes of an object that depend on promises e.g. XHR.

Please make ObjectProxy and ArrayProxy public API. I don't believe this combo is only unique to Ember Data. Anyone writing custom data persistence benefits from the same pattern as Ember Data does. Why does this need to be private API?

I understand ObjectController and ArrayController are deprecated and extend ObjectProxy and ArrayProxy respectively. I understand the confusion for new developers using those proxied controllers and I understand that Controllers will be replace with Components in 2.0. However I don't see why the ObjectProxy and ArrayProxy need to be private API.

Is there another way to use PromiseProxyMixin aside from combining a proxy object/array?

Below is the use case I have for a data persistence library…

A utility object (RelatedProxyUtil) with a factory creates proxies, to be used in a computed property:

/**
  Proxy for the requested relation, resolves w/ content from fulfilled promise
  @method createProxy
  @param {Resource} resource
  @param {Ember.ObjectProxy|Ember.ArrayProxy} proxyFactory
  @return {PromiseProxy} proxy
*/
createProxy: function (resource, proxyFactory) {
  const relation = this.get('relationship');
  const url = this.proxyUrl(resource, relation);
  const service = resource.container.lookup('service:' + pluralize(relation));
  let promise = this.promiseFromCache(resource, relation, service);
  promise = promise || service.findRelated(relation, url);
  let proxy = proxyFactory.extend(Ember.PromiseProxyMixin, {
    'promise': promise, 'type': relation
  });
  proxy = proxy.create();
  proxy.then(
    function (resources) {
      proxy.set('content', resources);
    },
    function (error) {
      console.error(error);
      throw error;
    }
  );
  return proxy;
}

A helper that uses the proxy util and returns a computed property:

/**
  Helper to setup a has one relationship to another resource
  @method hasOne
  @param {String} relation
*/
export function hasOne(relation) {
  let util = RelatedProxyUtil.create({'relationship': relation});
  let path = ['relationships', relation, 'links', 'related'].join('.');
  return Ember.computed(path, function () {
    return util.createProxy(this, Ember.ObjectProxy);
  }).meta({relation: relation, kind: 'hasOne'});
}

Computed property public API

I just want to test the waters on making the computed properties API public. It was delayed in the past here because of streaming. I'm now using some private API here and here, specifically _dependentKeys and _getter. I would love to use public versions of these.

cc @ebryn

Gathering feedback: Support native ES properties for computed properties

This issue is intended to gather feedback on making computed properties gettable and settable via native properties (in addition to the get/set methods).

For example, instead of:

myObj.get('computedProperty');
myObj.set('computedProperty', 1234);

You could do:

myObj.computedProperty;
myObj.computedProperty = 1234;

Benefits:

  • No more issues when a native property is swapped out with a computed property, requiring all API consumers to switch to get/set.
    • Alt: no more defensively coding with get/set all the time "just in case". *
  • Better autocomplete/discoverability in REPLs and IDEs (and hover support in Web Inspector).
  • Less typing.
  • More "natural" JS.

* Even if you do this, it can't be applied across the board since you still have to deal with native/non-Ember objects which don't have get/set.

Drawbacks:

  • unknownProperty obviously won't work if you don't actually call get/set. unknownProperty is rarely used - classes tend to declare all of their actual properties. However, if your object actually takes arbitrary properties (like an ES Map), get and set will still be there for you.

Again, not proposing the removal/deprecation of get/set. If you like the methods better, or have use of unknownProperty then they will still be there for you. But I think it would be nice to use native accessors for the majority of cases where you don't even want unknownProperty.

Better compatibility with async/await function in test

Hi,

This issue is related to this other one.

I like the next 'async/await' feature proposed in es7. I saw in this article than it can works but I don't understand why because it will automatically fail if Ember.testing is true as you can see on this line.

My main goal is to have a cleaner syntax. I tried to do an action like this :

  actions: {
    async clone(model) {
      const clone = await model.clone();

      clone.set('name', clone.get('name') + ' - copie');
      clone.set('activity', model.get('activity'));
      this._nestedSave(clone, 'groups');
    }
  }

It works but I cannot test it because I have the message "You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in a run". I described the error in this SO question. I know I can use Ember.run but async/await become useless.

I saw I can set Ember.testing to false but there will be problems later.

I think a better way to manage async/await feature is needed.

What you think?

Provide read-only access to window.location

Summary: Provide an Ember-y way to read the full URL contained in window.location that also supports testable ways of changing the value.

Context: I have a site-brand service that computes critical branding elements based on the domain used to access the app. First invocation is from index.js to set the window title with ember-cli-document-title, so router-based solutions aren't sufficient. Testing the naive implementation of the service would require changing window.location directly which has undesirable consequences.

Alternatives:

  1. Someone suggested using this.get('router.url') but it's undefined in index.js and only returns the route path.
  2. Someone suggested using Ember.Location, but access to the required information in it is private and/or undocumented. The same thing goes for the underlying ember-metal/environment it relies on for location.
  3. Wrap access to window.location or memoize it in a way that can be overridden by tests.

I'm doing #3, but feel something more Ember-y would be of general utility.

I understand we're talking about SPAs, so the protocol and domain parts won't change over the app's lifetime. I also suggest read-only because external links should be handled as links and internal ones should be handled through the router. It should be changeable during testing, but without the side effects you'd get from changing window.location.

Thoughts?

List all open RFCs and order them by progression/stability.

(We had a small discussion about this at EmberCamp.)

It would be nice to have a list of all current open (and recently landed in canary/beta/stable) RFCs with some kind of ranking/ordering on how far along the RFC process these RFCs are. Currently this is not easy to discern unless you pedantically keep up with every RFC opened.

I would like to propose we copy the way TC39 keeps track of their open RFCs. Although i'd like to have the stage numbers replaced with meaningful keywords.

My use case is that I try to follow RFCs to keep up with changes being made to Ember, as RFCs are currently the best source for this.

Introduce `resumeTest` to complement `pauseTest`?

The current implementation of pauseTest does its job well but it would be nicely complemented by introducing a way to resume the test that gets paused.

One particular use case for wanting this is to encourage developers to enable easier debugging/development against Acceptance tests. It's great to pause a test and try changing some things and then resume the test to ensure the rest of the flow works.

One drawback, however, is that any "resume" function would need to be bound to the global context (window in almost all cases) so that users can easily invoke it from the console.

I know I've seen implementations of this before, but couldn't seem to find any issue pointing to whether or not discussion was had on adding it to the core test helper.

Expose a parentElement property for (tagless) components

Components have an element property that gives you the DOM element of the component itself. Getting its parent is pretty easy, using element.parentElement or this.$().parent(). But these approaches fail when dealing with tagless components, which have no element and no this.$() either. Obviously, they still have a parent though!

So far I have used this utility function:

import Ember from 'ember';

const { get, $ } = Ember;

export default function getParent(view) {
  if (get(view, 'tagName') === '') {
    // Beware: use of private API! :(
    if (Ember.ViewUtils && Ember.ViewUtils.getViewBounds) {
      return $(Ember.ViewUtils.getViewBounds(view).parentElement);
    } else {
      return $(view._renderNode.contextualElement);
    }
  } else {
    return view.$().parent();
  }
}

This seems to work for all Ember versions (pre and post Glimmer2), but is obviously pretty hacky as it is using private APIs. And there does not seem to be any way to get the parent element for a tagless component using just public APIs, unless I am overlooking something!?

So my suggestion would be to introduce a parentElement property, in analogy to the element property.

An example use case: I want to make a tooltip component, that should be used like this:

<button>
  Create
  {{bs-tooltip title="Just create something"}}
</button>

The tooltip component must have access to its parent element, to attach event listeners to it, but should not (until the tooltip is actually shown) add anything to the DOM. Thus a tagless component.

Any thoughts?

Make `classNameBindings` a computed property

See the discussion here: emberjs/ember.js#13229.

It would come down to being to do something like this:

export default Ember.Component.extend({
  classNameBindings: function() {
    if (conditionA) {
      return ['propertyA', 'propertyB'];
    } else if (conditionB) {
      return ['propertyB'];
    } else {
      return [];
    }
  }.property(...)
});

or whatever logic one wishes in classNameBindings.

The advantages are that one can decide what properties one adds as a CSS class, potentially saving computations as Ember's lazy evaluation makes sure that a property is never computed if it's never used.

Do DOM manipulation in requestAnimationFrame

requestAnimationFrame is function which runs before the document's layout is calculated and the page is rendered. In some cases, using requestAnimationFrame to insert elements before a paint cycle would be useful. An example case where this would be useful would be for a progress bar element which listens for mouseDown, mouseUp and mouseMove events and changes css in the component accordingly. Something like a component option similar to classNameBindings or classNames to set variables which are refreshed on raf instead. What do you think?

Migrating to C++

Hello, I do not know if this idea is beyond the scope of ember, or even if it is possible to implement, but I think it would be a big step for the development of Ember.

This is abou migrating Ember to C++ for subsequent compilation to Javascript using asm.js.

The idea behind this is as follows:

Using Ember CLI to develop as usual, using Javascript, as has been done so far. Ember CLI, will compile that to C++ code, and then convert it to javascript using ASM, which is sent to the browser.

On the other hand, having an intermediate code in C ++, allows ember to run faster in hybrid applications, since you could run this code in iOS, and Android using JNI, which would make ember in the most appropriate tool for the development of native applications, due to its high performance, so minimal amount of javascript will be executed in mobile device, and all the logic will be executed in C++.

Deprecate the usage of Ember.on for Component's lifecycle events.

Request

Deprecate this:

Ember.Component.extend({
  someRandomName: Ember.on('didInsertElement', function() {
  })
});

In favor of:

Ember.Component.extend({
  didInsertElement: function() {
    this._super(...arguments);
  }
});

Reasoning

Ember.Component.extend({
  doA: Ember.on('willInsertElement', function() { },
  doB: Ember.on('willInsertElement', function() { }
})

The order in which doA and doB happens is unknown. This code might be the result of a refactoring. Or, a developer new to the code base not noticing that the event is being observed already. Subtle bugs can be easily introduced.

It is also easier to read and understand the behavior of a component if there is a single place where all the event dependent code is executed. Tracking down all the different pieces of code that are executed at different moments in the lifecycle is cumbersome and can be easily avoided by using overrides.

One argument that might come up against overrides is:

what if people forgets to call super? that can introduce bugs too!

It is easier to know that you always have to have that call inside the hook, there is determinism. Whereas keeping track of all the Ember.ons that might be cohabiting an object is not straightforward. When reading the code, you have to keep a mental map of all the pieces that might be executed by a hook; the cognitive load is high.

Make factory deprecation warnings more helpful

This deprecation warning is difficult to understand, and easily improved. The following message provides some information, but not enough to fix the problem:

Ember Inspector (Deprecation Trace): In Ember 2.0 service factories must have an isServiceFactory property set to true. You registered (subclass of Ember.ObjectProxy) as a service factory. Either add the isServiceFactory property to this factory or extend from Ember.Service.

In my case, I had to temporarily patch my copy of Ember to get it to tell me which service was offending. It would be helpful to include parsedName.fullName in the message.

Have link-to helper and action cooperate by closing on transitions.

I have been looking around a lot and could not find anything, sorry if I just missed it.

Now we have the ability to create closure actions with the {{action}} helper and pass actions to be invoked by a component, it opens a wide array of possibilites. For instance, we can let a component display some data, and pass it a closure action it will trigger when the user clicks on something.

{{my-list data=library.books nameClicked=(action "selectBook") }}
<ul>{{#each books as |book|~}}
    <li><button {{action attrs.nameClicked book}}>{{book.name}}</button></li>
{{~/each}}</ul>

That example does not actually close over anything but the handler, but that is enough. This is very powerful when cascading sub-components, saving the hassle of forwarding actions on the way up.

I believe it would be useful to allow passing a transition as an action this way. That is:

{{my-list data=library.books nameClicked=(link-to 'library.book.edit' library) }}

Exact syntax could vary. Maybe it could even be another helper instead of link-to.

So, more to the point, I believe it would be useful to be able to build a callable action that, when triggered, will initiate a transition.

  • Route name is mandatory.
  • Additional link-to parameters are closed over (in the example, library is closed over).
  • Parameters passed when sending the action are appended (in the example, book is appended, so transition will have both library and book).

This behavior can be obtained right now by making an action on the controller that invokes transitionTo, but that's a bit clumsy.

I'd like to discuss Webpack

With all the new modularization happening I'd like to champion swapping Broccoli out for Webpack in Ember CLI.

Without writing a big wall of text, here's my short outline of why:

  • Broccoli is (pretty much) exclusive to Ember.
  • Vue, Angular, React and a good few independant projects use Webpack, I've tried some of these in the past week and it's suprisingly easy to add dependencies.
  • Webpack will give Ember CLI better support for generic packages. I think this will become the key pain point of keeping Broccoli around.
  • Webpack has better documentation on writing plugins for webpack, this is pretty much undocumented in Broccoli's case.
  • I'm sure we can make it work for existing pure ember (non-'cli') addons, without breaking much. I guess we'll need a transition period for the addons that do, although some will become obsolete too.

TL;DR I think it is time to admit Broccoli is a dead end street and that Webpack will bring more benefits to Ember.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.