Why does my routing not work in Ember Js? - javascript

I'm working on a todoApp with a rails API and frontend as Ember.
I've followed this tutorial Ember todo App
However, it a bit old and I kinda lost in my routing.
I've a todos.hbs which should be rendered localhost:4200/, but it is a clear page.
Here's what my router.jslooks like :
import EmberRouter from '#ember/routing/router';
import config from './config/environment';
const Router = EmberRouter.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.map(function() {
this.route('todos', { path: '/' });
});
export default Router;
And my routes/todos.js:
import Route from '#ember/routing/route';
export default Route.extend({
model: function() {
return this.store.find('todo');
}
});
On my application.hbs, there's only an ```{{outlet}}
and my todos.hbs looks like this :
<section id="todoapp">
<header id="header">
<h1>todos</h1>
{{input type="text" id="new-todo" placeholder="What needs to be done?" value=newTitle action="createTodo"}}
</header>
<section id="main">
<ul id="todo-list">
{{#each itemController="todo"}}
<li {{bind-attr class="isCompleted:completed isEditing:editing"}}>
{{#if isEditing}}
{{input insert-newline=(action "acceptChanges")}}
{{else}}
{{input type="checkbox" checked=isCompleted class="toggle"}}
<label {{action "editTodo" on="doubleClick"}}>{{title}}</label>
<button {{action "removeTodo"}} class="destroy"></button>
{{/if}}
</li>
{{/each}}
</ul>
<input type="checkbox" id="toggle-all">
</section>
</section>
<footer id="info">
<p>Double-click to edit a todo</p>
</footer>
{{outlet}}
So now, I dont know where the mistake is, it only rendered me a blank page. If anyone can explain what is wrong into my work, I would appreciate.
UPDATE
I've found that a troubles appear in my application.js, here's what it looks like now, if that can help :
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
host: 'http://localhost:3000/api'
});

As Joe has already mentioned, store.find('todo') has been removed and from what I can see it was removed in 2015 but I am not 100% sure about that 🤔 You are likely to find other large issues following such an old tutorial and using the latest Ember. Have you seen the official tutorial on the Ember Guides site? https://guides.emberjs.com/release/tutorial/ember-cli/ there is always a lot of people making sure that it is as up-to-date as possible!
I will continue to try to answer your question but I do strongly recommend that you try a slightly more modern tutorial in the meantime 😂
Joe is indeed correct that you need to update the call in your route to use the updated method this.store.findAll('todo') and you should be able to see that recommended in your console output if you bring it up (you can usually right-click anywhere on the page and select 'Inspect Element' and then click the console tab)
As you can see the error says:
Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type. Error: Assertion Failed: Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.
Once I update that method so we're using findAll() it gives me a new error:
Error while processing route: todos No model was found for 'todo' Error: No model was found for 'todo'
Which means I need to create the file models/todo.js. If you do look at a more modern tutorial it will probably recommend that you use a generator to generate this file such as: ember generate model todo.
I then added your adapter and this is where I need to stop because I don't have the backend server running on my local machine so it will always fail for me 😄
You can see the code I was using to test this here: https://ember-twiddle.com/14bab300c47493c10a9de69efd591092
If you haven't used Ember Twiddle before I would highly recommend it if you are trying to ask a question here on Stack Overflow, on the Ember Discord server or on the Ember forums. If you are able to recreate your issue on an Ember Twiddle then you are very likely to be able to get a helpful response 🎉
Let me know if you have any questions and I hope this has been helpful 👍

I noticed that your routes/todos.js calls this.store.find('todo');. Using store.find(type) has been removed. I think you have to call this.store.findAll('todo');

Related

EmberJS template component suddenly not rendering on page

I'm following this Ember tutorial and I've suddenly run into an issue where my rental-listing.hbs template component stops rendering. It started when I began implementing the map service.
I don't understand where this could be happening. I've copied the code from parts of the GitHub repository that I thought were relevant but to no avail.
I have a rental.hbs template that looks like so:
<div class="jumbo">
<div class="right tomster"></div>
<h2>Welcome!</h2>
<p>We hope you find exactly what you're looking for in a place to stay.</p>
{{#link-to "about" class="button"}}
About Us
{{/link-to}}
</div>
{{outlet}}
Which in turn has a template component called rental-listing.hbs:
<article class="listing">
<a
onclick={{action "toggleImageSize"}}
class="image {{if this.isWide "wide"}}"
role="button"
>
<img src={{this.rental.image}} alt="">
<small>View Larger</small>
</a>
<div class="details">
<h3>{{link-to this.rental.title "rentals.show" this.rental class=this.rental.id}}</h3>
<div class="detail owner">
<span>Owner:</span> {{this.rental.owner}}
</div>
<div class="detail type">
<span>Type:</span> {{rental-property-type this.rental.category}} - {{this.rental.category}}
</div>
<div class="detail location">
<span>Location:</span> {{this.rental.city}}
</div>
<div class="detail bedrooms">
<span>Number of bedrooms:</span> {{this.rental.bedrooms}}
</div>
</div>
<LocationMap #location={{this.rental.city}}/>
</article>
The only thing I have added to the above is the line <LocationMap #location={{this.rental.city}}/> but it still doesn't work if I remove it.
The console shows me no errors and I can actually see I am getting the three dummy objects I want from Mirage:
So I'm definitely getting the objects and from what I see I'm doing everything necessary in the templates to render it but they aren't. Should I be looking somewhere else?
Are you able to provide a link to your example? By having each piece of the ember application you mention it would be best to answer definitely. I can give a general answer with strategies for debugging the template.
The conventions behind ember.js make understanding the "whys" frustrating at first and possibly opaque. Ember's handlebars implementation governs how values are populated and accessed within templates using very specific rules. Ember treats templates (handlebars files) differently depending on whether it is for a route or component. Component's have an isolated context and must receive values by explicit passing in or dependency injection. Then, you can use such values in a component's template by accessing those properties with {{this.somePassedInValue}}.
In the super-rentals app, it appears the rental index route invokes the components responsible for displaying the individual units. I found this in app/templates/rentals/index.hbs.
<li><RentalListing #rental={{rentalUnit}} /></li>
The route template iterates over the list of filteredResults. Each of these is the rentalUnit. A good first step would be to use the {{log}} helper to print out that the value of rentalUnit to ensure it is what you expect.
Alternatively, you could try cloning https://github.com/ember-learn/super-rentals and applying the changes you want to make step by step from the master branch. By doing so, you could easily undo a single change to see what caused something to not show up as expected.
<LocationMap #location={{this.rental.city}}/>
to be written as below
<LocationMap #location={{this.rentals.city}}/>
may be typo error.
also repeat this for there place in that template.
Because the model name in the console is rentals not rental

How to make Laravel/Vue implementation show individual entry

I'm trying to integrate Laravel with Vue, and further down the line Nuxt, in the hope that I can integrate snazzy page transitions like the ones shown on http://page-transitions.com into my websites.
I've been reading a tutorial about using Vue with Laravel; https://scotch.io/tutorials/build-a-guestbook-with-laravel-and-vuejs, and I was pleased to find that Laravel ships with a Vue implementation, so I thought there'd be quite a lot of info on how to use the two in combination, but there doesn't seem to be.
I completed the tutorial and made the guestbook as it was described. I'm now trying to build upon that.
Specifically, Im trying to create individual pages for each of the guestbook entries.
I do have quite a bit of experience using Laravel, but only what I've described above with Vue.
So, in order to create the individual pages, I've created a new route in the routes/web.php file;
Route::get('signature/{id}','SignaturesController#show')->name('signature');
I've then created a new code block in app/Http/Controllers/SignaturesController.php to deal with this request;
public function show()
{
return view('signatures.signature');
}
I've created the specified view in resources/views/signatures/signature.php;
#extends('master')
#section('content')
<div class="container">
<div class="row">
<div class="col-md-12">
<signature></signature>
</div>
</div>
</div>
#endsection`
And I've created the vue file that should integrate with this view in resources/assets/js/components/Signature.vue;
<template>
<h1>Signature</h1>
</template>
<script>
export default {
}
</script>
Finally, I've registered the component in resources/assets/js/app.js and reran npm run dev.
This has worked to an extenet, I can view the file at the expected url; http://transitions.localhost/signature/1.
My question is, how do I get the data related to the signature with the ID of 1 into the page? I can't even echo out {{ id }} or {{ signature }}.
Any other resources that you've found helpful regarding this subject would also be greatly appreciated. Thanks for taking the time to read through all of that, does anyone know where I go from here?
You will need to pass the data to your vue component
Maybe something like this?
In your view:
#section('content')
<div class="container">
<div class="row">
<div class="col-md-12">
<signature :signature="{{ $signature }}"></signature>
</div>
</div>
</div>
#endsection
In your vue component:
<template>
<h1>This signature has the ID of: {{ signature.id }}</h1>
</template>
<script>
export default {
props: ['signature']
}
</script>

Meteor publish and subscribe not working

I have a fairly novice question and am hoping someone can help me.
I have the following code in which subscribe/publish is not working:
if (Meteor.isServer) {
Meteor.publish('items', function () {
return Items.find({});
});
}
if (Meteor.isClient) {
Meteor.subscribe("items");
}
In my template:
<template name="items">
<div class="ui segment">
<div class="ui relaxed list">
{{#each item in items}}
<div class="item">
<img class="ui avatar image" src="http://placehold.it/20x20">
<div class="content">
<a class="header">{{item.text}}
</div>
<button class="delete">×</button>
</div>
{{/each}}
</div>
</div>
</template>
But nothing gets output. However when I add:
Template.items.helpers({
items: function () {
return Items.find({});
}
});
I do see the list properly. Why is this so? Also I am clearly confused as to why someone would want to use subscribe/publish along with the template helpers.
I suggest you read Data flow from the database to the UI: Three layers of Meteor
You are creating a publication labeled: items. Then you are subscribing to a publication labeled deals. This will not work as the labels must match for the subscription to work.
If adding that template helper then shows the data in the UI, you must have the autopublish package in your app. It will be autopublish, not your pub/sub, that is sending the client the data the client puts in it's mini-mongo Items collection.
So pub/sub gets the data from the server to the client, but doesn't display it. That is why you need the template helper, to get the data from the client's mini-mongo collection into the format the templates require.
You must subscribe() using the same name as used in the publish(). In your case (pay attention to 'items'):
/server:
Meteor.publish('items', function () {
return Items.find({});
});
/client:
if (Meteor.isClient) {
Meteor.subscribe('items');
}
The publish/subscribe link is telling meteor to send all docs in the 'Items' collection to minimongo on the client. Now, the purpose of the template helper is to tell meteor that you want to reactively update the template any time a document changes in Items.
A good reference on the subject: https://www.discovermeteor.com/blog/understanding-meteor-publications-and-subscriptions/

display number of items in ember.js

I need a very easy thing and looking on the web the solutions founded tell me that my code is right. But clearly isn't.
I just need to display how many notes(models) I have in my app:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title> Notes and bookmarks </title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<script type="text/x-handlebars" data-template-name="index">
<div class="wrap">
<div class="bar">
<input type="text" class="search" />
<div class="bar-buttons">
<button> NEW </button>
<button> HOME </button>
</div>
</div>
<aside>
<h4 class="all-notes">All Notes {{all}}</h4>
{{#each item in model}}
<li>
{{#link-to 'note' item}} {{item.title}} {{/link-to}}
</li>
{{/each}}
</aside>
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="main">
<section>
<h2>Hellooo</h2>
</section>
</script>
<script type="text/x-handlebars" data-template-name="note">
<section>
<div class="note">
{{#if isEditing}}
<h2 class="note-title input-title"> {{edit-input-note value=title focus-out="modified" insert-newline="modified"}} </h2>
<p class="input-body"> {{edit-area-note value=body focus-out="modified" insert-newline="modified"}} </p>
{{edit-input-note value=url focus-out="modified" insert-newline="modified"}}
{{else}}
<h2 {{action "editNote" on="doubleClick"}} class="note-title" > {{title}} </h2>
<button {{action "removeNote"}} class="delete"> Delete </button>
<p {{action "editNote" on="doubleClick"}}> {{body}} </p>
{{input type="text" placeholder="URL:" class="input" value=url }}
{{/if}}
</div>
</section>
</script>
<script src="js/libs/jquery-1.9.1.js"></script>
<script src="js/libs/handlebars-1.0.0.js"></script>
<script src="js/libs/ember-1.1.2.js"></script>
<script src="js/libs/ember-data.js"></script>
<script src="js/app.js"></script>
<script src="js/router.js"></script>
<script src="js/models/note_model.js"></script>
<script src="js/controllers/note_controller.js"></script>
<script src="js/controllers/notes_controller.js"></script>
<script src="js/views/note_view.js"></script>
</body>
</html>
My model:
Notes.Note = DS.Model.extend ({
title: DS.attr('string'),
body: DS.attr('string'),
url: DS.attr('string')
});
Notes.Note.FIXTURES = [
{
id: 1,
title: 'hello world',
body: 'ciao ciao ciao ciao',
url: ''
},
{
id: 2,
title: 'javascript frameworks',
body: 'Backbone.js, Ember.js, Knockout.js',
url: '...'
},
{
id: 3,
title: 'Find a job in Berlin',
body: 'Monster, beralinstartupjobs.com',
url: '...'
}
]
And my notes controller:
Notes.NotesController = Ember.ArrayController.extend ({
all: function () {
var notes = this.get('model');
return notes.get('lenght');
}.property('model')
});
I think that's all the important code for make this work but if you need others part I will add.
Why i can't see the number of my notes in {{all}} ?
In your notes.hbs template you should be able to do {{length}}.
I made a few adjustments to the code that you provided and got it to work the way that i think you expected it to work. I am going to try to explain where I think you may have been sent for a loop as it relates to your App. Ember takes some getting use to for sure.
One thing that is important is that Ember uses naming conventions to help you wire up and associate your Router, Routes, Controllers, Templates correctly with each other and also help you to look at code and know what Ember expects. Ember also gives you free stuff, yaaay for free stuff.
So when Ember boots up you get some default assets for free the ApplicationRoute, ApplicationController, and the application template these are always present in Ember even if you never explicitly define them. However if you need to use them just define them and add whatever code. In addition to those you get an IndexRoute, IndexController and index template which are present at the top of Ember like those other assets.
Remember the application template, which is at the highest level of the app, think of it as the parent of all templates. Other templates will be put into it and rendered, including the index template that you got for free. Now this is where things get a little tricky.
If you define a router like this in Ember for example. You still have that index template which you can use as you were and you also now have a template called note.
App.Router.map(function() {
this.resource('note');
});
Can you guess the names for the Controller and Route associated with the note resource using Ember naming conventions? I'll leave that for homework. Now when Ember boots with this Router if you defined a index template (just like you were) it will automatically be pushed into the application templates {{outlet}}and rendered. A note on the application template if all its doing is basically being and 'outlet' to render stuff Ember will do that just fine by default.
Behind the scenes the default application template may look something like this. I just put the <script> tags to highlight its the application template.
<script type="text/x-handlebars">
{{outlet}}
</script>
The template without a data-template-name is used as the application template. You can put in data-template-name="application" if you like but its not necessary unless you are using build tools. Now back to the Router stuff.
If you define a Router like this something happens that is important to realize.
App.Router.map(function() {
this.resource('note', { path: '/'});
});
By adding {path: '/'} in that resource you are overriding the /, which is the based url of you application. Now '/' is not associated with index template that you got for free its the note template. When Ember boots it will automatically push the note template into the application outlet.
Moving along, in your code you had few other things that were also conflicting. Remember with naming conventions if ask Notes.NotesController for something Ember by default will look for a Notes.NotesRoute and a notes template, attention to the pluralization, but in your code your code you have a note template.
The other conflict is with the index template, again with the naming conventions Ember is going to look for the IndexController for the {{all}} property and IndexRoute to the supply the model. In your code its on the Notes.NotesController.
And finally dont forget if you are using and adapter to define it:
Notes.ApplicationAdapter = DS.FixtureAdapter.extend({});
Sorry for the long answer but i hope it clear up things
Here the jsBin.
http://emberjs.jsbin.com/UPaYIwO/7/edit
Happy Coding!!
PS. You could have put {{model.length}} in the template and it would have accomplished the same thing. But in Ember there is a few ways to do the same thing.
There is also a typo:
return notes.get('lenght');
Lenght should be length;
return notes.get('length');

Combine linkTo and action helpers in Ember.js

I need to combine linkTo and action helpers in Ember.js. My code is:
{{#link-to 'index'}}<span {{action 'clear'}}>Clear</span>{{/link-to}}
But I would like to make this something like this:
{{#link-to 'index' {{action 'clear'}} }}Clear{{/link-to}}
And also:
<li>
{{#link-to 'support'}}
<span {{action 'myAction' 'support'}}>Support</span>
{{/link-to}}
</li>
To:
<li>
{{#link-to 'support' {{action 'myAction' 'support'}} }}Support{{/link-to}}
</li>
How can I achieve this?
Solution
Check my answer for Ember 2.0 compatible, OK for SEO solution.
Ember Link Action addon
This is OK for SEO solution!
Install addon
ember install ember-link-action
Usage
You can pass closure action as invokeAction param to {{link-to}} component:
{{#link-to 'other-route' invokeAction=(action 'testAction')}}
Link to another route
{{/link-to}}
To pass parameters to action you can use:
{{#link-to 'other-route' invokeAction=(action 'testAction' param1 param2)}}
Link to another route
{{/link-to}}
Compatibility
Automated test suite confirms that addon works with 1.13 up to latest Ember 3 releases.
It works with a release, beta and canary versions of Ember.
Addon GitHub repository. Contributions are welcome.
Update: See Michael Lang's comment below for Ember 1.8.1+
The problem with Myslik's answer (not using link-to at all but instead using an action and then transitionToRoute) is that it's useless for SEO, search engine bots will see nothing.
If you want what your link is pointing to to be indexed, it's easiest to have a good old <a href=x> in there. It's best to use link-to so that your link URLs are kept in sync with your route URLs. The solution I use gives both an action to do the work and a handy link-to to index the pages.
I override some functionality of Ember.LinkView:
Ember.LinkView.reopen({
action: null,
_invoke: function(event){
var action = this.get('action');
if(action) {
// There was an action specified (in handlebars) so take custom action
event.preventDefault(); // prevent the browser from following the link as normal
if (this.bubbles === false) { event.stopPropagation(); }
// trigger the action on the controller
this.get('controller').send(action, this.get('actionParam'));
return false;
}
// no action to take, handle the link-to normally
return this._super(event);
}
});
Then I can specify which action to take and what to pass the action in Handlebars:
<span {{action 'view' this}}>
{{#link-to 'post' action='view' actionParam=this}}
Post Title: {{title}}
{{/link-to}}
</span>
In the controller:
App.PostsIndexController = Ember.ArrayController.extend({
actions: {
view: function(post){
this.transitionToRoute('post', post);
}
}
}
This way, when I cache a rendered copy of the page and serve that to an indexing bot, the bot will see a real link with an URL and follow it.
(note also that transitionTo is now deprecated in favour of transitionToRoute)
None of these combinations will work in Ember.js, but you do not need to combine these two helpers. Why don't you just use action helper and let it bubble to controller or route? There you can use transitionToRoute in controller or transitionTo in route.
For example in controller you could have code like this:
App.PostsController = Ember.ArrayController.extend({
clear: function () {
// implement your action here
this.transitionToRoute('index');
}
});
This works fine in 1.6.0-beta.5:
<span {{action "someAction"}}>
{{#link-to "some.route"}}
Click Me
{{/link-to}}
</span>
The link will happen and then the click will bubble up to the action handler. It's documented (albeit indirectly) here.
Edit: corrected syntax in opening link tag
I like Cereal Killer's approach for its simplicity, but unfortunately it exhibits a problem for me. When the browser navigates to another route, it restarts the Ember application.
As of Ember 2.6, the following simple approach does the trick:
<span {{action 'closeNavigationMenu'}}>
{{#link-to 'home' preventDefault=false}}
Go Home
{{/link-to}}
</span>
This achieves the following:
navigates to route 'home'
action 'closeNavigationMenu' is invoked
on mouseover, browser displays link that will be followed (for SEO and better UX)
browser navigation does not result in reboot of Ember app
Having the same problem, i found this simple solution:
{{#linkTo eng.rent class="external-button"}}<div class="internal-button" {{action "updateLangPath"}} >X</div>{{/linkTo}}
then, managing the css classes external-button and internal-button in the stylesheet, i made sure that the "internal-button" was covering the whole "external-button" area; in this way it is not possible to click on the external-button without clicking on the internal-button.
It works well for me; hope it can help...
This is how I solved this in our demo application for the O'Reilly Ember.js book: https://github.com/emberjsbook.
You can see the complete source here: https://github.com/emberjsbook/rocknrollcall
In the view:
{{#if artistsIsChecked}}
{{#if artists.length}}
<h3>Artists</h3>
<ul class="search-results artists">
{{#each artists}}
<li><a {{action 'viewedArtist' this.enid }}>{{name}}</a></li>
{{/each}}
</ul>
{{/if}}
{{/if}}
And the controller:
App.SearchResultsController = Em.ObjectController.extend({
actions: {
viewedArtist: function(enid) {
this.transitionToRoute('artist', enid);
},
viewedSong: function(sid) {
this.transitionToRoute('song', sid);
}
},
needs: ['artists', 'songs'],
artistsIsChecked: true,
songsIsChecked: true,
artists: [],
songs: []
});
This is what it would look like after Ember 3.11.0 with the on modifier.
<LinkTo
{{on "click" this.recordMetrics}}
#route="post.see-all"
#model={{#model}}
#bubbles={{false}}>
Link Me
</LinkTo>
bubbles shown just to illustrate the LinkTo API.
https://blog.emberjs.com/ember-3-11-released/
Ember's link-to tags use routes to open new views, so you can perform whatever functionality you wanted to put in the link's 'action' attribute in the setupController method of the target route instead of in a controller action.
See here in the Ember guide:
http://emberjs.com/guides/routing/setting-up-a-controller/
This only works if you want to perform the action every time the route is accessed, however, as opposed to with specific links.
Make sure to include the controller.set('model', model); line along with whatever else you put in there.

Categories