display number of items in ember.js - javascript

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');

Related

Why does my routing not work in Ember Js?

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');

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>

New to Meteor and helper function is not working

I am learning meteor and I cannot get my helper function to return some static text.
<head>
<title>LeaderBoard</title>
</head>
<body>
<h1>Leaderboard</h1>
<p>{{player}}</p>
</body>
in JS
if(Meteor.isClient){
Template.leaderboard.helpers({
player: function(){
return "text";
}
});
}
This only returns the Leaderboard header
UPDATE:
changed to:
LeaderBoard
<body>
<h1>Leaderboard</h1>
<p>{{player}}</p>
</body>
<template name="leaderboard">
{{player}}
</template>
and JS is still the same and it still does not work
So, there are few mistakes you made. Let's deconstruct it.
What is a template?
A template is a piece of code that renders into DOM and can be manipulated using helpers, events and such. For you to use any template, there has to exist one. They can either be put into your app from packages or made by yourself. In this particular case, you're looking for the latter.
To define a template, pick any HTML file or create a new one and define it in HTML way:
<template name="theTemplate">
Hello, I am the template.
</template>
So now you can inject this template wherever in the DOM you want, using this syntax:
<body>
<h1>My super app</h1>
<div>{{> theTemplate}}</div>
</body>
It will render into
<body>
<h1>My super app</h1>
<div>
Hello, I am the template.
</div>
</body>
or, in fact, something a bit uglier since Meteor preserves all the indentation and stuff.
How can I put changeable text into the template?
You're already right that you need helpers for that. A helper is a function that returns an Object (be it String, Number, etc.) which is being injected as is, as if it was document.writed.
Helpers for any template are defined in this way:
Template.theTemplate.helpers({
coolestString: function () {
return 'I am the coolest string put by a helper.';
}
});
Note that Template object contains theTemplate property. It happened exactly after Meteor picked up your template definition and then stored it into an object with helpers method (and a bunch of other useful methods, too).
If you remove theTemplate template definition (aka HTML), the Template object will not have its theTemplate property, and the whole thing will throw a TypeError since you try to access a property of undefined.
How do I put values returned by helpers into the template?
Simply use {{ ... }} syntax. Say, you have a helper coolestString and you need to fetch value from it, whatever it is, and put into h1 tag:
<template name="theTemplate">
<h1>{{ coolestString }}</h1>
</template>
Note the difference between {{> ...}} and {{ ...}}. The former inject a template, the latter inject a value from current context; template's helpers stay within its root context (or just forget it if you don't understand contexts yet).
So, what should I do to use template in my app?
To make a conclusion,
Define a template.
Optionally, define its helpers. Each helper should return a string, a number, an array or an object.
Access helpers' values within the template using {{ ... }} syntax.
Inject the template into your document using {{> ...}} syntax.
That's it.
Okay, show me the whole code!
In myCoolestApp.html,
<body>
{{> theTemplate}}
</body>
<template name="theTemplate">
{{ coolestAppName }}
</template>
And in myCoolestApp.js,
if (Meteor.isClient()) {
Template.theTemplate.helpers({
coolestAppName: function () {
return 'My super cool app!';
}
});
}
Done!
But what if I want to omit template?
In general, a helper by definition belongs to some template, so the hierarchy of injection is the body, then the template, then the helper. But it is possible to inject a helper right into document body and omit intermediary template. You do so with Template.registerHelper method:
Template.registerHelper('theHelper', function () {
return 'I am helper'; // add some logic here and see how it works; hint: reactively.
});
What you do then is just put it into your document:
<body>
{{ theHelper }}
</body>
which gets rendered to
<body>
I am helper
</body>
The principle behind Template.registerHelper is DRY, don't repeat yourself. Sometimes you need to provide exactly same data to more than one template, so at first you would think you have to copy helpers code. But this method helps avoid unnecessary repetition.
You can use more complex objects, covered with more complex logic, this way, or you can even put Mongo collections into the document directly.
Option 1
In case you dont have multiple pages/screens for your app. Edit your template html like this.
<head>
<title>LeaderBoard</title>
</head>
<body>
<h1>Leaderboard</h1>
{{> leaderboard}}
</body>
<template name="leaderboard">
{{player}}
</template>
PS:- {{player}} refers to the template helper "player" and {{> leaderboard}} refers to a template ( This is handlebar syntax ).
Option2 : Your template should look like this.(Assuming you have multiple pages/screens for you app - it would be better if you use some kind of router)
A main layout page - call it master.html
<head>
<title>LeaderBoard</title>
</head>
<body>
</body>
A template named leaderboard. call it leaderboard.html
<template name="leaderboard">
{{player}}
</template>
Then your helper with the same code that you provided in the question.
This should work.

How to have nested routes without nested templates

I have ember routes set up like so:
App.Router.map(function() {
this.resource("subreddit", { path: "/r/:subreddit_id" }, function() {
this.resource('link', { path: '/:link_id'} );
});
});
But I want the to view each link in a completely separate template. In other words, I want to render a different block of html, rather than render the link html into subreddit's {{outlet}}.
When you hit /r/xxx in the browser Ember will look for two templates related to subreddit. First it looks for 'subreddit' and then it looks for 'subreddit/index'. If 'subreddit' if found, then it is rendered and then if 'subreddit/index' is also found, it is rendered into the {{outlet}} of 'subreddit'. If 'subreddit' is not found Ember will just move on to 'subreddit/index'. The 'subreddit' template is also rendered for any sub-paths that are nested under /subreddit, such as the 'link' template for /r/xxx/yyy. 'subreddit' is kind of like a "per model layout" template that allows you to wrap (decorate) all of the sub-path templates.
Something like this should let you keep your nested routes, and allow you to use Ember default behavior.
<script type="text/x-handlebars" data-template-name="subreddit">
<p>A static header bar for this subreddit could go here, or not.</p>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="subreddit/index">
<p>
All of the details of the subreddit go here, this will be rendered
into the {{outlet}} of "subreddit".
</p>
</script>
<script type="text/x-handlebars" data-template-name="link">
<p>
Link view goes here. This template will replace "subreddit/index"
in the {{outlet}} of "subreddit".
</p>
</script>
If you want to render the links in separate templates you should not nest your routes:
App.Router.map(function() {
this.resource("subreddit", { path: "/r/:subreddit_id" });
this.resource('link', { path: '/:link_id'});
});
A different approach you can take could be to use named outlet's and override renderTemplate of the corresponding route and render the template in the place of the named outlet's, have a look here for more info on that: http://emberjs.com/guides/routing/rendering-a-template/
Hope it helps.

Ember view - how to manipulate DOM after UI rendered without modifying the original source code?

For some reasons, I can only add javascript after Ember application is created (i.e. all UI inited).
The HTML looks like this:
<div id="ember21643" class="ember-view form_field ticket_type_id has-ticket-type-field">
<label for="">
<script id="metamorph-249-start" type="text/x-placeholder"></script>
Type
<script id="metamorph-249-end" type="text/x-placeholder"></script>
</label>
<div id="zd_mn_385" class="zd-selectmenu zd-selectmenu-root zd-state-default">
<button id="zd_mn_386" class="zd-selectmenu-base" role="button" tabindex="0" style="width: 131px; "><span class="zd-selectmenu-base-arrow zd-icon-triangle-1-s"></span><span id="zd_mn_387" class="zd-selectmenu-base-content">-</span></button>
</div>
</div>
It's easy to use jQuery to target the to do direct DOM modification but I worry that it will break the Ember application.
Is there a proper way to change this view, for example:
append/prepend a text to the div container
change the text to something else instead of "Type" as in the above example.
Using DOM inspection, this view looks like it can be accessed from:
Ember.View.views.ember21643
And
Ember.View.views.ember21643._childViews[0]
is pointing to "label". So I set
Ember.View.views.ember21643._childViews[0]._lastNormalizedValue = "ABC"
but it's still showing "Type" on the screen so probably this is not the way to do.
Please help. Thanks alot. (I'm new to Ember).
I'm not sure if i'm missing your point but, if I wanted to change the text in an ember view, I think I would use the Ember bindings.
template
<div id="someView" type="text/x-handlebars">
This sentence has a dynamic {{ end }}
</div>
view
App.someView = Ember.View.extend({
end : 'conclusion',
templateName: 'someVIew' //not really necessary with new router to be explicit
})
view with binding
App.someView = Ember.View.extend({
endBinding : 'contoller.end',
templateName: 'someVIew' //not really necessary with new router to be explicit
})
Does any of that help? :)

Categories