View management with Ember.StateManager (and not Ember.Router) - ember.js

I'd like to user Ember to create an 'informational sign' type of application; The data displayed will be updated on a regular basis, but there is no user input or interaction. The application is configured and initialized based on URL parameters provided by an administrator. The layout and content of the application will change depending on the data in the feed the application is monitoring.
Ember.Router seems like overkill for this task because I don't need/can't have URL-based routes mapped to application state. Ember.StateManager seems perfect because it allows me to programmatically transition between states depending only on conditions met within the logic of my application, ignoring the current URL. The deprecated Ember.ViewState seems like it was the way to manage views when using Ember.StateManger.
What is the current best practice for managing views in the DOM with Ember.StateManger?
Is there a way to do what I'm describing with Ember.Router instead?
Thanks,
Aaron

After reading your primary explanation, I feel that you dont need any states at the moment. You need diferent application stated defined when application needs different behaviour in those states. Looks like your application behaviour is not changing but just view.
So you can just use some handlebars condition helpers to make this work along with some derived attribute in your controller indicating whether there is any current advisory.
{{#view App.myView}}
{{#if hasAdvisory}}
<div class="col-2">
<div class="col1">
{{#each bus}}
//bus details
{{/each}}
</div>
<div class="col2">
//advisory details
</div>
</div>
{{else}}
<div class="col-1">
<div class="col">
{{#each bus}}
//bus details
{{/each}}
</div>
</div>
{{/if}}
{{/view}}
Please explain more like if you just need this or do you plan any different application behaviours when you have advisory and when you dont have.

In general, the same techniques used to manage views and controllers in Ember.Router-based apps can be used with Ember.StateManager. Specifically, using outlets with Em.Controller#connectController is an excellent way to switch views that is independent of state management.

Related

How to fix warning "interaction added to non-interactive element no-invalid-interactive"

I just upgraded my Ember addon from version 3.0 to version 3.8, and I get this warning now:
Interaction added to non-interactive element no-invalid-interactive
An example of this is something like:
<div class="some-class" onclick={{action "selectDate" "today"}}>
<div> more content </div>
</div>
When you click the action, it should take you to a new route.
What are my options to fix it the right way, so that it is accessible?
The solution here depends on what the action should do.
Refactoring an action that triggers a transition
Since this action takes the user to a new route, it should be a link element, <a> and not a button. This gives assistive technology/screen reader users a clue that interacting will take them somewhere new in the app.
This can be refactored to a link-to in Ember, which will wrap the content in <a>:
{{#link-to someRoute}}
<div> more content </div>
{{/link-to}}
someRoute could be a computed property if it needs to be informed by multiple pieces of data. Otherwise, it could be a string.
Refactoring an interaction that keeps you on the same page
In cases where the action does not take you to a different page, it may be appropriate to use a <button>. An example of this would be a button that expands a collapsible container or toggles a setting. However, the w3 validator tells us that you can't put divs inside of buttons. You can use Phrasing Content that is non-interactive, such as <span>.
<button class="some-class" onclick={{action "toggleSomething"}}>
<span> more content </span>
</button>
Learn More
To catch more accessibility problems in an app, try out ember-a11y-testing which audits your app for problems and gives you a report of how to fix them.
This question was answered as part of "May I Ask a Question" Season 2 Episode 3. If you would like to see us discuss this answer in full you can check out the video here: https://youtu.be/nQsG1zjl8H4

EmberJS: Nothing handled the action

Ember newbie. Using 2.3.0. To an existing application I need to add a button that toggles content on and off the screen. Following the existing code patterns, I added the following two files.
app/components/help.js
import Ember from 'ember';
export default Ember.Component.extend({
actions: {
toggleHelp() {
this.toggleProperty('isShowingHelp');
}
}
});
templates/components/help.hbs
<div class="help">
<a href="#" {{action "toggleHelp"}}>help</a>
</div>
{{#if this.isShowingHelp}}
<p>HELPHELPHELP</p>
{{/if}}
And then in various *.hbs files I'm adding {{partial "components/help"}} to get the button to show up where it is needed.
The button renders as expected as
<div class="help">
help
</div>
But when I click, I get the error, "Nothing handled the action 'toggleHelp'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble."
I checked the Ember documentation and saw that this matches the instructions.
I think the issue might be because I am calling it as a partial, but none of the other options (view, render, outlet) seems to apply to my limited case.
As per this answer, I tried {{action "toggleHelp" target='component'}}, but then the error when I click turned into, "ember.debug.js:29112 Uncaught TypeError: Cannot read property 'send' of undefined."
I'm at a total loss... Can anyone point out what I'm missing here? Thanks!
Update:
If I copy toggleHelp into the controller going along with one of the .hbs files, then the link works properly. But surely the right way cannot be to put this in multiple controller files? (And when I try to put toggleHelp in controllers/application.js, in hopes that would cover everywhere (?!), I'm back to the original error.)
Your problem is indeed {{partial "components/help"}}!
In general you should not use partials. To call a component you use {{component-name}}.
However components in Ember 2.3 need to have a - in their name. So help is not valid!
rename your component into something like my-help. So app/components/my-help.js for your js and templates/components/my-help.hbs. Then you can just do {{my-help}} to use the component.

Can I let a user customize a component's template?

I'm making a sortable component. You could imagine a simple implementation having the following API:
{{sortable-list content=orderedQuestions tag='ul' itemTag='li'}}
But, that offers pretty limited template customization. Ideally I'd like the API to allow something like this:
{{#sortable-list content=orderedQuestions tag='ul'}}
<li>
<h2>{{title}}</h2>
<div>Some more {{details}}</div>
</li>
{{/sortable}}
where this block template gets used for each sortable item. Is this possible? I tried something like this for the component's template:
{{#each item in content}}
{{#with item}}
{{yield}}
{{/with}}
{{/each}}
but this doesn't work, since the block template the user passes into the component has the controller as its context.
Is what I'm after possible?
The exact thing you're trying to do is not currently possible.
Take a look at this Github issue to see a lot of discussion around component use cases like this. In particular take a look at Trek's first comment.
An alternative is to break your component into multiple components:
{{#sortable-list content=orderedQuestions tag='ul'}}
{{#each orderedQuestions}}
{{#sortable-item tag='li'}}
<h2>{{title}}</h2>
<div>Some more {{details}}</div>
{{#sortable-item}}
{{/each}}
{{/sortable}}
If you think about components in terms of existing HTML elements you can see that it kind of looks a little bit like a select which has options inside. To make this work it's likely that the sortable-items would need to communicate with the sortable list. One option is to use parentView in your component to get access to the parent.
Take a look at this talk from Ryan Florence to get more ideas about how to deal with composable components.
Update
Updated my answer to include an each around {{sortable-item}} to change the context.
Reading through the Ember each helper it seems that it would be possible for a component to do what you want but it looks really hairy.

Can a Ember.Component have both a block and non-block form?

I would like to build an Ember.Component that can be used either in block form, or without a block when some default behavior is desired.
For example, in block form:
{{#my-helper}}
...
{{/my-helper}}
Or non-block form:
{{my-helper}}
Where the helper template is somehow able to detect that there is not a block and behave accordingly. For example, it would be nice if there was some way to detect the block:
{{#if hasBlock}}
{{yield}}
{{else}}
default output
{{/if}}
For my requirements, I need to have some way to output something only if there's not a block.
Any ideas how to do this?
update:
If you're confused by why my question is the same as the accepted answer it's because Ember happened to adopt new syntax that is exactly what I originally imagined up as desirable. When I first asked this question it turned out there was an undocumented way to do this using {{#if template}} but that has since been deprecated with Ember 2.x and there's new syntax {{#if hasBlock}} which happens to match how I phrased my question.
Inside the Component you'd want to check the value of hasBlock
{{#if hasBlock}}
{{yield}}
{{else}}
<p>Default content for inline (non-block) form of the component.</p>
{{/if}}
Here's a JSBin : http://jsbin.com/IWEKere/1/edit
The link to the docs is here: http://emberjs.com/api/classes/Ember.Component.html#property_template
The docs don't explicitly say that the template attribute is used in this way. Since the Ember.Component class inherits from the Ember.View class, it can be inferred that the component template acts like the Ember.View layout template.
"template" has been deprecated in favour of partial, eg.
{{#if partial}}
{{yield}}
{{else}}
<p>Default content for inline (non-block) form of the component.</p>
{{/if}}
Accessing template directly is currently deprecated, but there is a feature-flagged hasBlock property (which basically does !!template under the hood) that should be used in this case.
The feature flag is ember-views-component-block-info
Here's a link to the merged pull request: https://github.com/emberjs/ember.js/pull/10461

Updating backed array in Ember.js rc1 does not propogate to view

I am trying to upgrade a partially built UI to the latest Ember.js rc1 and it has turned into a very big rewrite job thanks to the dramatically changed API. Most info out there (and here) has been rendered useless. I've had to go through the documentation again several times to get things partially working but there are a lot of loose ends. Here is a biggie. The views do not update like they did under the previous version. I'm missing something that must have to do with rerender, {{outlet}} or something else that I'm not aware of. The ember guides seem to need updates.
The template is very simple:
<script type="text/x-handlebars" data-template-name="index">
<button {{action "addOne"}}>add one</button>
<ul>
{{#each item in controller}}
<li>{{item.title}}</li>
{{/each}}
</ul>
</script>
When clicked, the button adds a new element to the backed array. The console logs show that the array is growing, but the template does not change. Here is a jsfiddle to illustrate how far I've gotten. Can anyone figure out what needs to be added?
I modified your example to highlight the fact when we use arrays in Ember, that we are using Ember arrays (Ember.A() or Em.A() if you want to make explicit this fact). From my understanding, you can use the methods Em.A().addObject and Em.A().removeObject to achieve the basic functionality using the Ember.Object getter and setter methods, (i.e. .get() & .set()) .
In order be properly observed by the Ember application, it is important to use the Ember getters and setters.
A modified version of your fiddle.