Extending {{link-to}} with Ember-cli - ember.js

This question is similar to the unanswered Extending link-to.
I'm trying to extend the {{link-to}} helper to output additional attribute bindings. However the attributes do not appear in our HTML. Heres what we have:
//views/link-to.js (normally coffeescript)
import Ember from 'ember'
var LinkToView = Ember.LinkView.reopen({
attributeBindings: ['data-toggle', 'data-placement', 'title']
});
export default LinkToView;
The rendered output is this:
define('app/views/link-to', ['exports', 'ember'], function (exports, Ember) {
'use strict';
var LinkToView;
LinkToView = Ember['default'].LinkView.reopen({
attributeBindings: ['data-toggle', 'data-placement', 'title']
});
exports['default'] = LinkToView;
});
When its called and its rendered output:
// Any .hbs file
{{#link-to 'account'
class='header-link'
data-toggle='tooltip'
data-placement='right'
title='Account'
}}
<span class="glyphicon glyphicon-cog" aria-hidden="true"></span>
{/link-to}}
// Rendered...
<a id="ember615" class="ember-view header-link" href="/account" title="Account">
<span class="glyphicon glyphicon-cog" aria-hidden="true"></span>
</a>
Where are we going wrong? I know it has something to do with the resolver or how we're calling it.
Thanks.

For Ember 2.0+
Create directory app/reopens
Create file app/reopens/link-component.js
import Ember from 'ember';
Ember.LinkComponent.reopen({
attributeBindings: ['data-variation', 'data-offset', 'data-content','data-any']
});
in app.js import it
import LinkComponent from './reopens/link-component';
That's all. For ember-cli < 2.0 replace LinkComponent with LinkView

So its probably not the rightest answer, but I discovered on accident that if you put any sort of extensions or overrides like this into route/applaction.js's beforemodel hook that it works perfectly:
// routes/application.js
export default Ember.Route.extend({
beforeModel: function() {
Ember.LinkView.reopen({
attributeBindings: ['data-toggle', 'data-placement', 'title']
});
})
});

File: app/reopens/link-component.js
If this can help others for generic data-* for Ember 2.x .
import Ember from 'ember';
Ember.LinkComponent.reopen({
init: function() {
this._super();
var self = this;
// bind attributes beginning with 'data-'
Object.keys(this).forEach(function(key) {
if (key.substr(0, 5) === 'data-') {
self.get('attributeBindings').pushObject(key);
}
});
},
});

Related

Overriding LinkComponent EmberJs 1.13.15

Im Using EmberJs 1.13.15 and Ember-CLI , i was trying to slightly modify the main LinkComponent behavior by adding the following code:
app/components/nav-link-to.js:
import Ember from 'ember';
export default Ember.LinkComponent.extend({
tagName: 'li'
});
app/templates/components/nav-link-to.hbs:
{{yield}}
and im using this component in:
app/templates/nav-bar.hbs:
<ul class="nav navbar-nav">
{{#nav-link-to 'index'}}Home{{/nav-link-to}}
</ul>
but whenever i open the nav-bar template in the browser nothing shows up
and in ember inspector's console it shows the following error
Uncaught TypeError: Cannot read property 'slice' of undefined
Any help?
Thanks in advance.
You will have to add the params in your component. Also you will have to call this._super in init method of component. Below is the working component code for extended link-to.
import Ember from 'ember';
export default Ember.LinkComponent.extend({
tagName: 'li',
positionalParams: 'params',
init: function() {
this._super(...arguments);
},
didReceiveAttrs: function() {
this.attrs.params = this.get('params');
this.attrs.hasBlock = true;
}
});

Disable button in Ember with return value of function

I've been trying to create an Ember Component with the latest version on Ember. Here is the part of the component I'm having trouble with though:
//app/templates/components/page-r.hbs
<div class="pager-container">
{{#each range as |page|}}
<button type="button" disabled={{isCurrentPage(page)}}>{{page}}</button>
{{/each}}
</div>
//app/components/page-r.js
import Ember from 'ember';
const PageR = Ember.Component.extend({
settings: Ember.computed('params.[]', function() {
return this.get('params')[0];
}),
range: [4,5,6],
currentPage: 1,
isCurrentPage(pageIndex) {
return this.currentPage === pageIndex;
},
});
PageR.reopenClass({
positionalParams: 'settings'
});
export default PageR;
There is more to the component than that, but my question is this:
Is it possible to make the disabled attribute update based off of the result of an action like I'm trying to do? If so, how?
The above code doesn't even compile, but I've tried a number of variations and haven't gotten any of them to work. I can get the disabled property to work based off a pure boolean value, but can't figure out how to get this to execute the function and utilize the boolean value that is returned from it to fuel the disabled attribute. Any help would be greatly appreciated!
You need to use another component to create the computed property.
// app/templates/components/page-r.hbs
<div class="pager-container">
{{#each range as |page|}}
{{page-button page=page currentPage=currentPage}}
{{/each}}
</div>
// app/templates/components/page-button.hbs
<button type="button" disabled={{isCurrentPage}}>{{page}}</button>
// app/components/page-r.js
import Ember from 'ember';
const { computed } = Ember;
const PageR = Ember.Component.extend({
settings: computed('params.[]', function() {
return this.get('params')[0];
}),
range: [4,5,6],
currentPage: 1
});
PageR.reopenClass({
positionalParams: 'settings'
});
export default PageR;
// app/components/page-button.js
import Ember from "ember";
const { computed } = Ember;
export default Ember.Component.extend({
tagName: 'span',
isCurrentPage: computed('currentPage', 'page', function() {
return this.get('currentPage') === this.get('page');
}),
});

Ember nested route show.hbs params not working

I am trying to show a 'show' template for a list of items.
My index.hbs works as follows:
route/index.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('item');
}
});
template/items/index.hbs
items/index.hbs
<ul>
{{#each model as |item|}}
<li>
{{#link-to 'items.show' item}}
{{item.name}}
{{/link-to}}
</li>
{{else}}
<li>No contacts found.</li>
{{/each}}
</ul>
However, when I click a link that is generated, it brings me to the correct route (localhost:4200/items/1), however, it gives me the following error: Error while processing route: items.show Assertion Failed: You may not pass 'undefined' as id to the store's find method Error: Assertion Failed: You may not pass 'undefined' as id to the store's find method
Here is my show.js and hbs:
routes/show.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return this.store.findAll('item', params.id);
}
});
and templates/items/show.hbs
{{name}}
here is router.js
import Ember from 'ember';
import config from './config/environment';
var Router = Ember.Router.extend({
location: config.locationType
});
export default Router.map(function() {
this.resource('items', function() {
this.route('show', {path: ':item_id'});
});
});
I can not figure out when its not working! I read that params is not sent from index to show..but then?!
Thank you in advance. Any exaggerated answer would be most appreciated.
Hope this helps. http://ember-twiddle.com/147af82f6fa69bf97414
After looking at your code snippets closely, I realized that inside your item:model hook you are passing params.id to store.findAll return this.store.findAll('item', params.id), however in your router.js you specified it as item_id. You should be using the same param name used in your route definition.

Im trying to understand ember and ember cli conventions and file structure

I have set up a simple api and a new ember app using ember cli
However, while I can get a full list of 'items' to appear, I can't get a single item to work using params.
I have my files set up like the following:
/models
item.js
/routes
/items
index.js
show.js
/templates
/items
index.hbs
show.hbs
application.hbs
index.hbs
items.hbs
router.js
For reference, here is what I have in the files
I set up my models/item.js a follows:
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string')
});
I added my code to my router.js
import Ember from 'ember';
import config from './config/environment';
var Router = Ember.Router.extend({
location: config.locationType
});
Router.map(function() {
this.route('items', function() {
this.route('show', { path: '/:item_id' });
});
});
export default Router;
Then I created my templates/index.hbs
{{outlet}}
And finally, added my templates/items/index.hbs
<ul>
{{#each model as |item|}}
<li>
{{#link-to 'items.show' item}}
{{item.name}}
{{/link-to}}
</li>
{{/each}}
</ul>
This works as intended.
However, when I click a link (/items/1), it no longer performs as expected. It will show the items/show.hbs correctly assuming I do no use any handlebars variables ({{item.name}}). For example, If I just include text, this is my items/show.hbs it will display the text. When I add in, {{name}} it displays a blank page
Here is my templates/items/show.hbs
{{name}}
and my routes/items/show.js
import Ember from 'ember';
export default Ember.Route.extend({
model(params) {
return this.store.queryRecord('item', params.item_id);
}
});
What am I doing wrong?
Thanks in advance!
It looks like you're not using reference to model when using it in template
Here is my templates/items/show.hbs
{{name}} < This is a model's property- name
Correct usage: {{model.name}}
and my routes/items/show.js
import Ember from 'ember';
export default Ember.Route.extend({
model(params) {
return this.store.queryRecord('item', params.item_id);
}
});
Way of using hash
return Ember.RSVP.hash({
something: store.find('y', { study: params.study_id }),
somethingElse: store.find('x', 1),
});

ember.js - ember-cli: ember-data not available on child view

I'm using the latest ember-cli and currently testing it, creating very simple app using ember-data and http-mock for RESTAdapter - ember generate http-mock api-server
Single post get from the API:
http://localhost:4200/api/api-server/posts/1
Result
{"post":
{
"id":1,
"title":"How to write a JavaScript Framework",
"author":"Tomhuda Katzdale",
"body":"Lorem ipsum dolor sit amet"
}
}
Here are all the relevant codes:
Adapters
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
namespace: 'api/api-server'
});
Model
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
author: DS.attr('string'),
body: DS.attr('string')
});
router.js
import Ember from 'ember';
var Router = Ember.Router.extend({
location: EmbercliDataENV.locationType
});
Router.map(function() {
this.route('application');
this.resource('posts', function() {
this.resource('post', { path: ':post_id' });
});
});
export default Router;
Routes (posts and post) - view and child view
posts route
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('post');
}
});
post route
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return this.store.find('post', params.post_id);
}
});
template
posts.hbs
<h2>Posts List</h2>
<ul>
{{#each}}
<li>
{{#link-to 'post' this}}{{title}}{{/link-to}} | {{author}} | {{body}}
</li>
{{/each}}
</ul>
{{outlet}}
post hbs
<h2>Single Post</h2>
<p>Post title: {{title}}</p>
<p>Post author: {{author}}</p>
<p>Post body: {{body}}</p>
THE PROBLEM: if you look at the screen-cap below, in the chrome ember debugger, the single post model is hooked to the post route but is not printed in the post.hbs
Using just the ember starter kit, I got no problem at all with the exact same app.
Thank you for any help, cheers
UPDATE
The following is the exact same Ember app coded using the starter kit, host in xampp and using PHP Slim framework for REST Api. Working FINE!
try to fix your data, because post is nested in posts, try this:
{"post":[
{
"id":1,
"title":"How to write a JavaScript Framework",
"author":"Tomhuda Katzdale",
"body":"Lorem ipsum dolor sit amet"
}]
}
check within your posts hbs if the data is visible, then post should work fine
After browsing the Ember.js forum I got the answer there - http://discuss.emberjs.com/t/strange-behavior-w-retrieving-model-from-controller/6155
It seems when using the Ember generate controller command, you end up with Ember.Controller, not Ember.ObjectController or Ember.ArrayController lol.
I edit my post controller from: (generate by the Ember generate controller command)
export default Ember.Controller.extend({
});
to
export default Ember.ObjectController.extend({
});
and now the model is binding :D
<h2>Posts List</h2>
<ul>
{{#each}}
<li>
{{#link-to 'post' post}}{{title}}{{/link-to}} | {{author}} | {{body}}
</li>
{{/each}}
</ul>
{{outlet}}
1.instead of 'this' use post, hope this will fix the issue
http://emberjs.com/guides/templates/links/#toc_adding-additional-attributes-on-a-link