Using group-helper with ember-app-kit : assertion fails - ember.js

I'm trying to use Ember.js group-helper with Ember App Kit.
Since group has no dash, app/helpers/group.js can't be resolved, so I'm loading the helper explicitly in app.js, as explained in EAK docs.
app/helpers/group.js
export default function(option) {
var data = options.data,
fn = options.fn,
view = data.view,
childView;
childView = view.createChildView(Ember._MetamorphView, {
context: Ember.get(view, 'context'),
template: function(context, options) {
options.data.insideGroup = true;
return fn(context, options);
}
});
view.appendChild(childView);
}
in app.js
import GroupHelper from 'appkit/helpers/group';
Ember.Handlebars.registerBoundHelper('group', GroupHelper);
in a template
<ul>
{{#group}}
{{#each}}
<li>{{prop1}} {{prop2}}</li>
{{/each}}
{{/group}}
</ul>
I get an assertion failed :
registerBoundHelper-generated helpers do not support use with Handlebars blocks.
(the app works fine without the group helper)
I know the group-helper is experimental, but does that mean it's not working with current Ember release ?
If this is supposed to work, what am I missing ?
Edit after #Stakoov's comment:
I've updated from Ember 1.4.0-beta6 to 1.4.0 and I'm using Handlebars 1.3.0.
I've tried the EAK way, renaming group to group-item (since EAK resolver needs a dash).
app/helpers/group-item.js
export default Ember.Handlebars.makeBoundHelper(function(options) {
// (...snip...)
});
in the template :
<ul>
{{#group-item}}
{{#each}}
<li>{{prop1}}</li>
{{/each}}
{{/group-item}}
</ul>
Still the same Assertion failed.

Related

Adding component dynamically in Ember

using
Ember : 1.13.11,
Ember Data : 1.13.8,
ember-cli : 1.13.12
I want to add a component dynamically to webpage - this webpage is template of another component don't think that it will make any difference-. Here is my code snippet in which I try to add a component named LyricsEditorLine to <div> tag, somehow like this
agenda-alpha/components/lyrics-editor.js
import Ember from 'ember';
import LyricsEditorLine from 'agenda-alpha/components/lyrics-editor-line';
export default Ember.Component.extend({
afterRenderEvent:function(){
LyricsEditorLine.create().appendTo($("#in"));
},
init:function(){
Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
this._super();
}
});
agenda-alpha/templates/components/lyrics-editor.hbs
<div id='in'> </div>
every time this gives me
'Uncaught Error: Assertion Failed: You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead'
Looked for ContainerViewhere found that it is deprecated
Most of the answers that I found are not using ember-cli and being a beginner makes it harder to understand
I want to be able to add components as much as the user needs
I think you probably want the {{component}} helper which allows to dynamically render a component.
{{component "componentName" param1=paramValue param2=anotherParamValue}}
Which means you can have (made up example)
{{component "lyrics-editor-line" line=line}}
One the best things is that componentName can be a bound property
{{component componentName line=line}}
And in your controller/component:
componentName: Ember.computed('prop1','prop2', function() {
if (this.get('prop1') === 'A') {
return 'my-component-a';
}
return 'default-component';
}),
line: computed('prop3', function() {
return this.get('prop2');
})
Also, you can have the component helper inside an each loop (example taken from the Ember documentation)
{{#each model as |post|}}
{{!-- either foo-component or bar-component --}}
{{component post.componentName post=post}}
{{/each}}

From within an ember component life cycle hook, how can I determine if the component is being invoked in block form?

Per the Ember guides, you can determine if a component is being rendered in block format from within the template using the hasBlock keyword:
// foo-component.hbs
{{#if hasBlock}}
block mode
{{else}}
something else
{{/if}}
How do I do this from within foo-component.js?
import Ember from 'ember';
export default Ember.Component.extend({
didInitAttrs: function() {
// hasBlock is not defined here
if ( this.get('hasBlock') ) {
}
}
});
You could check for template property of Component, but such behavior is deprecated:
if (this.get('template')) {
console.log('Component has block!');
}
Working demo.
Per sbatson's comment, using hasBlock in the template is not supported.

Not rendering/removing sidebar based on route

Something I've been experimenting around with Ember for a couple of hours and can't work out. Hopefully it's just a terminology issue that I'm getting stumped on as I read through the Ember docs.
I have an application, that, for the most part, consists of a sidebar/top bar (called wrapper), and a footer.
My basic application.hbs looks like this (I'm using Ember App Kit to provide structure):
{{partial "wrapper"}}
{{outlet}}
{{partial "footer"}}
If this was the state of my application, it would work pretty well. Page content loads in the {{outlet}} fine.
My main issue is how to break out of this template structure in an "Ember" way (and preferably without going all jQuery and removing DOM elements willy-nilly).
I have a few routes that I don't want the wrapper and the footer to show on (they're full page login/forgot password routes, and a couple of minimal interface/no distractions modes).
I experimented with trying to remove the sidebar and footer by making the default template (application.hbs):
{{#if showWrappers}}
{{partial "wrapper"}}
{{/if}}
{{outlet}}
{{#if showWrappers}}
{{partial "footer"}}
{{/if}}
Where showWrappers is in the ApplicationController:
export default Ember.Controller.extend({
showWrappers: function() {
var routes = ['login'],
currentPath = this.get('currentPath'),
show = true;
routes.forEach(function(item) {
var path = new RegExp('^' + item + '*');
if (!Ember.isEmpty(currentPath.match(path))) {
show = false;
}
});
return show;
}.property('currentPath'),
});
Attemping to transition to /login from / using {{link-to}} returns in an error: Uncaught Error: Cannot perform operations on a Metamorph that is not in the DOM presumably because I'm removing things Ember wanted to keep (I am using {{link-to}} and {{bind-attr}} in the sidebar, so there are bindings there).
Aware that I could use actions and jQuery to hide elements of the page and bring them back for the "distraction free" mode, but I'd prefer to learn how to structure templates and use Routes with the renderTemplate hook potentially using this.render (?) to blow away the current DOM and rebuild from a different base (rather than application.hbs).
Thoughts? More than happy to clarify.
I have discovered disconnectOutlet, and have converted my partials into outlets:
{{outlet wrapper}}
{{outlet}}
{{outlet footer}}
Made my ApplicationRoute render to them by default:
export default Ember.Route.extend({
renderTemplate: function() {
this.render();
this.render('wrapper', {
outlet: 'wrapper',
into: 'application'
});
this.render('footer', {
outlet: 'footer',
into: 'application'
});
}
});
and then on the LoginRoute, I just run this.disconnectOutlet for both wrapper and footer, and seems to work pretty well.

Handlebars error: Could not find property 'query-params' although Feature activated

I am trying to use query-params in my route / controller but the handlebars helper is causing this error:
Uncaught Error: <(subclass of Ember._MetamorphView):ember689>
Handlebars error: Could not find property 'query-params' on object
.
This error is caused by this link to helper:
{{#link-to 'betround.stats' (query-params game=id) }}
<li {{bind-attr class="isPast:small"}}> {{team1}} {{scoreT1}} : {{scoreT2}} {{team2}} (gameid: {{id}})</li>
{{/link-to }}
I have already upgraded Ember and Handlebars
DEBUG: Ember : 1.4.0-beta.4
DEBUG: Ember Data : 1.0.0-beta.4
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery : 2.0.3
As well as enabled the query-params-new feature:
<script type="text/javascript">
ENV = {FEATURES: {'query-params-new': true}};
</script>
<script src="bower_components/jquery/jquery.js"></script>
<script src="bower_components/handlebars/handlebars.js"></script>
<script src="bower_components/underscore/underscore.js"></script>
<script src="bower_components/ember/ember.js"></script>
<script src="bower_components/ember-animated-outlet/ember-animated-outlet.js"></script>
<script src="bower_components/ember-data/ember-data.js"></script>
I am not sure if it is relevant but this is also my controller for the route:
GambifyApp.BetroundStatsController = Ember.ArrayController.extend({
needs: "betround",
queryParams: ['game'],
game: null,
filteredBets: function() {
var game= this.get('game');
var bets = this.get('model');
if (game) {
return articles.filterProperty('game', game);
} else {
return articles;
}
}.property('category', 'model')
});
It's a bug in that version of Ember, it's working in canary versions.
http://emberjs.jsbin.com/ucanam/3566/edit
They put in query-params-new by accident in v1.4.0-beta3, and removed it as of v1.4.0-beta4. The release version of 1.4.0 does not have this feature, as well as the beta versions of 1.5.0.
It looks like if you wanted to keep working with query-params-new, you'll either need to use the canary build (1.6.0) or revert to 1.4.0-beta3.
https://github.com/emberjs/ember.js/issues/4372#issuecomment-35175856

Ember cannot find my view

I have defined a View subclass MenuitemView to which I'm referring from a template (see below). But Ember doesn't find it. I keep getting this error:
Error: assertion failed: Unable to find view at path 'App.MenuitemView'. What am I missing?
Initialization code:
window.require.register("initialize", function(exports, require, module) {
var App;
App = require('app');
App.Router.map(function(){});
require('routes/IndexRoute');
require('templates/menuitem');
require('templates/application');
require('templates/index');
App.initData();
});
View definition:
window.require.register("views/MenuItemView", function(exports, require, module) {
var App;
App = require('app');
module.exports = App.MenuitemView = Em.View.extend({
templateName: 'menuitem',
visibility: function(){
if (App.selectedDishType && !App.selectedDishType === this.get('dish').get('type')) {
return 'invisible';
} else {
return '';
}
}
});
});
Template referring to view (templates/index.hbs):
{{#each item in content}}
{{view App.MenuitemView itemBinding=item}}
{{/each}}
View template (templates/menuitem.hbs)
<div class="dishitem">
<div class="dishimage">
{{thumbnail item.dish.identifier}}
</div>
<div class="dishdetails">
<p class="dishname">{{uppercase item.dish.name}}</p>
<p class="dishdescription">{{item.dish.description}}</p>
<ul class="packages">
{{#each package in item.packages}}
<li>
<span class="packageprice">€ {{package.price}}</span>
<span class="packagespec">
{{#if package.description}}({{package.description}}){{/if}}
</span>
</li>
{{/each}}
</ul>
</div>
</div>
The problem was caused by the fact that I was using Brunch for building the application and I have all the javascript components and templates in separate files. Brunch then compiles the templates to separate common.js javascript modules. The code in the template's compiled module does not have access to the view defined in the view module. The way to normally handle such dependencies is to add "require('my-other-module')" to the dependent module's javascript. But, as my template source is not javascript but handlebars, I cannot add this to the source.
The solution is to ensure your application namespace is globally available. You do this by not putting your application initialization code in a module, e.g. directly in your html, inside a script tag:
<script>
App = require('app');
</script>
What I do notice is that the 'item' part of menuitemview is sometimes upper case (views/MenuItemView), sometimes lower case. Could that be the source of the error message?
I encountered a similar problem with ember-tools, and the accepted answer set me on the right path. I'll leave my solution here for posterity.
I had my app set up like this:
var FooRoute = Ember.Route.extend({
...
renderTemplate: function() {
this.render();
this.render('Bar', {into: 'foo', outlet: 'bar', controller: 'foo' });
},
...
});
and in the template foo.hbs:
{{outlet bar}}
This was causing problems for the same sorts of reasons #RudiAngela mentions in the accepted answer. Instead of including a <script> tag, though, I just changed the {{outlet}} to a {{view}},
{{view App.Bar}}
and this solved the problem for me.