Emberjs toggle effect of dynamic data - javascript

I have a table loaded with dynamic data from an api. The <td></td> displays a company name and when clicked I want a div that has the companies information to be displayed. I saw a few examples and this is what I did:
Here is my handlebars:
{{#each m in model}}
<tr>
<td >
<p {{ action 'displayDetails' }}>{{m.name}}</p>
{{#if showDetails}}
<div class="company_details">
<p><strong>Wesbite URL: </strong>{{m.website}}</p>
<p><strong>Development Wesbite URL: </strong>{{m.dev_website}}</p>
</div>
{{/if}}
</td>
</tr>
{{/each}}
as you can see when you click on the name of the company the displayDetails action is called
here is my controller:
export default Ember.ArrayController.extend({
showDetails: false,
actions: {
displayDetails: function(){
this.toggleProperty('showDetails');
}
}
});
This works great; however if I click the company name all of the company details are displayed not just the company I clicked on. I obviously just want to display the specific detail of the company I clicked on how can I go about this?

Add a property to each item in the model named something like isDetailsShown.
You can modify you action by passing the item into the method.
<p {{ action 'displayDetails' item}}>{{m.name}}</p>
In the action, just toggle the property of the passed in item.
displayDetails: function(item){
item.toggleProperty('isDetailsShown');
}
Finally modify the if condition in the template to look like
{{#if item.isDetailsShown}}

Related

How to handle v-if with the back button in Vue.js?

I am using routing with Vue.js and am trying to use v-if to conditional display 2 divs. The first div is a list of items. The second div is the details of an item. A good example of what I am trying to do would be something similar to Gmail. You have your list of emails and when you click the subject, you are taken to a page that shows the whole email.
I have this somewhat working using v-if. In my data, I have a variable called view. When the page loads, this value is set to 'list', which shows the list div. When someone clicks something in the list div, this value switches to 'details'. and the details div shows.
The problem that I am running into is if the user hits the back button in the browser, the view variable does not get updated. This seems like it is a common scenario, so I am wondering if there is a better way to do this.
<div id="app">
{{ view }} //for debugging
<div class="list" v-if="view === 'list'">
<table>
<tr v-for="item in list">
<td><router-link v-on:click.native="doSomething" v-bind:to="'/items/' + item.id">{{ item.title }}</router-link></td>
</tr>
</table>
</div>
<div class="details" v-if="view === 'details'">
<router-view></router-view>
</div>
</div>
Snippets from my Vue declaration.
data: {
view : "list"
},
doSomething: function () {
var app = this;
app.view = "details";
}
Try this:
<div id="app">
{{ view }} //for debugging
<router-view></router-view>
</div>
And then add two routes:
{
path: '/',
name: 'emails',
component: Emails,
},
{
path: '/login',
name: 'email.show',
component: EmailShow,
}
After that Emails component should handle logic of showing all emails and EmailShow should handle showing just one email

How to create an Ember JS Master Detail where detail appears between rows of data

I'm trying to create a page that contains master/detail, which is obviously easy using a static {{ outlet }} in ember, however, I'd like the detail to slide down after the row that was selected. For example, on this page: http://jsbin.com/ijejap/1/edit, if the detail of the name was to appear after the currently selected name instead of at the bottom of the page.
The problem I'm trying to solve is that I can't have an outlet within a repeater so that when I click Row 1, I want the outlet to be positioned below Row 1, and when I click Row 2, I want the outlet after Row 2. In other words, I want to dynamically position an outlet, I think, unless there's another way to do it.
Ok, I finally made a conditionnal outlet depending on wether the user is selected or not, but I had to work with DS.Model and its FIXTURES to make this work.
To be brief, I added an action before the link to set a selected property on the user object and record which user is selected to prevent having two users at the same time.
The position of the {{outlet}} then depends on the current selected user.
Here's the template part:
{{#each model}}
<li {{action 'select' this}}>
{{#link-to "user" this}}{{first}}{{/link-to}}
</li>
{{#if selected}}
{{outlet}}
{{/if}}
{{/each}}
And the App.ApplicationController part:
App.ApplicationController = Ember.ArrayController.extend({
currentUser: null,
actions: {
select: function(newUser) {
var oldUser = this.get('currentUser');
if(newUser !== oldUser) {
if(oldUser)
oldUser.toggleProperty('selected');
this.set('currentUser', newUser);
newUser.toggleProperty('selected');
}
}
}
});
Finally, the model definition:
App.ApplicationRoute = Ember.Route.extend({
model: function() {
return this.store.find('user');
}
});
App.User = DS.Model.extend({
first: DS.attr(),
last: DS.attr(),
avatar: DS.attr()
});
Here's the link to the JSBin: http://jsbin.com/cilari/3/
You can make use of components power here.
I made it on JSBin : http://jsbin.com/zovos/2/
First, you declare your user details as a new component, say user-details :
<script type="text/x-handlebars" id="components/user-details">
<li>{{user.first}}</li>
<h2>
{{user.first}} {{user.last}}
<img {{bindAttr src="user.avatar"}} class="pull-right" width=50 />
</h2>
<dl>
<dt>First</dt>
<dd>{{user.first}}</dd>
<dt>Last</dt>
<dd>{{user.last}}</dd>
</dl>
</script>
Then you call it from your list, using the current user as the user in the component :
<script type="text/x-handlebars">
<div class="container">
<div class="row-fluid">
<ul class="nav nav-list span3 well">
{{#each model}}
{{user-details user=this}}
{{/each}}
</ul>
</div>
</div>
</script>
You add the selected property to your component and an action like expandDetails :
App.UserDetailsComponent = Ember.Component.extend({
selected: false,
actions: {
expandDetails: function() {
this.toggleProperty('selected');
}
}
});
Finally, you add the action to your component template and a conditional display on the selected property :
<script type="text/x-handlebars" id="components/user-details">
<li><a {{action "expandDetails"}}>{{user.first}}</a></li>
{{#if selected}}
<h2>
{{user.first}} {{user.last}}
...
</dl>
{{/if}}
</script>
And, of course, you get rid of your user route.
Here is a link to Ember's Guide that show this on a sample post example : http://emberjs.com/guides/components/handling-user-interaction-with-actions/
Hope this helps.
Are you looking for an accordion?
http://addepar.github.io/#/ember-widgets/accordion
I have an idea but unproved yet, maybe you can try it.
For detail, you only need one template. For master, you need write several named outlet (see: http://emberjs.com/guides/routing/rendering-a-template/) and place each below the corresponding item of master view.
When each master item has been clicked, you need pass a param to the detail route in order to let it know what kind of data should be populated.
The key part is the renderTemplate hook of route (see: http://emberjs.com/api/classes/Ember.Route.html#method_renderTemplate). You can take advantage of it because it allows you to specify which named outlet should be used to render the template.
Or you may load all details' data at once and cache it, then pass an identifier when master item got clicked, in this way you can filter the model in advance and get prepared for later renderTemplate use.
This is just an idea and currently don't have spare time to try it, but as your wish, you got the dedicated route, controller and model. I think it is highly doable, let me know it you make any progress.

Ember.js each loop with external/outbound link

Hello and thanks in advance for the help. I am using ember.js to make a basic site. I have an each loop, inside of which I want it to display a variable while linking to an external site (eg. google.com which I have stored as a different variable).
For some reason, when I am doing the inside the each loop, I am getting the error, "This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid." I cannot seem to figure out how to get this to go to an external site when clicked on. Here is my each loop and the example json.
{{#each}}
{{#link-to 'theme' theme tagName="tr"}}
<td class="noWrap">{{#link-to 'theme' title}}{{title}}{{/link-to}}</td>
<td>{{#link-to 'theme' this}}<img {{bind-attr src="image"}} \>{{/link-to}}</td>
<td class="tdCenter"><a {{bind-attr href="link"}}>{{price}}</a></td>
<td>{{description}}</td>
<td class="tdCenter">{{columns}}</td>
{{/link-to}}
{{/each}}
{
id: 1,
title: 'Title',
price: '$10',
description: 'random description',
columns: 1,
link:'https://google.com',
image: 'images/image.jpg'
}
and this is my theme route
App.ThemeRoute = Ember.Route.extend({
model: function(params) {
return App.THEMES.findBy('title', params.title);
}
});
Let me know if you have any ideas. Thanks again!
David B
If the {{#link-to 'theme' theme tagName="tr"}} is replaced with <tr> , the table row will be rendered without it being a link (unless this is not acceptable, unfortunately the link-to helper's purpose at that point is not clear to me).
So the result would be something like,
http://emberjs.jsbin.com/wuvazica/1#/theme/1
http://emberjs.jsbin.com/wuvazica/1/edit
hbs
<script type="text/x-handlebars" data-template-name="theme">
<table>
{{#each}}
<tr>
<td class="noWrap">{{#link-to 'theme' title}}{{title}}{{/link-to}}</td>
<td>{{#link-to 'theme' this}}<img {{bind-attr src="image"}} \>{{/link-to}}</td>
<td class="tdCenter"><a {{bind-attr href="link"}}>{{price}}</a></td>
<td>{{description}}</td>
<td class="tdCenter">{{columns}}</td>
</tr>
{{/each}}
</table>
</script>
By the way, the error that is shown it is due to the parameter theme in {{#link-to 'theme' theme tagName="tr"}}, if it is removed the error will go away but the rendered html will not function properly (at least what i noticed in the quick example i provided), because of the {{#link-to}} helper at that point.

Implementing an accordian-type view in Ember.js

In a toy application, I have a 'posts' template that shows all of the post titles. When you click each title, instead of heading to a 'show' view I want to expand down the rest of the contents of that post, directly inline.
I've considered having the postRoute reuse the postsRoute and set a flag that would then be checked against in the handlebars template to splat out the rest of the post content.
What would be a preferred 'Ember-ish' approach that would let a resource's singular view be rendered inline with its index view in the correct location?
I would suggest to define an itemController on PostsController which can take actions for individual post objects.
Then, in your template define the action (e.g. toggleBody) that toggles a property on the itemController. You can use this property to show or to hide the body of each post:
App.PostsController = Ember.ArrayController.extend
itemController: 'post'
App.PostController = Ember.ObjectController.extend
showBody: no
actions:
toggleBody: ->
#toggleProperty('showBody')
return false
<script type="text/x-handlebars" data-template-name="posts">
<ul>
{{#each}}
<li>{{title}} <span {{action toggleBody}} class='label'>Toggle</span>
{{#if showBody}}
<div>{{body}}</div>
{{/if}}
</li>
{{/each}}
</ul>
</script>
See also this jsFiddle for a working demo.

EmberJS Handling DOM Events using Views

I want to toggle a single form (see picture below) using views.
My code basically works when i add new formset it adds an empty bracket to json and then i
print the json out using eachloop
View template
{{#each view.anotherField}}
<div class="panel panel-default">
{{action 'toggleView' 'toggleViews' target='view'}}
...
</div>
{{#unless view.toggleViews}}
...content to toggle...
{{/unless}}
View controller??
actions: {
showMoreFields: function(){
this.get('anotherField').pushObject({name: ''});
,
toggleView: function(param){
this.toggleProperty(param);
}
In this given picture u can see ive toggled organization view to truth what i would like is to toggle only the clicked part not all of the forms. Is there a solution ?
Cheers,
Kristjan
If I understand correctly you need to handle events for specific parts/forms of your view. To achieve this there are at least three approaches,
1.Use the {{action}} helper passing the object you want to modify. Then in your function modify a property of that object and reflect that in your template e.g. toggle the form. Maybe in your case it could be something like ,
....
{{#each field in view.anotherField}}
<div class="panel panel-default">
{{action 'toggleView' field target='view'}}
....
2.Make a sub view/template (e.g. SubFormView) to accomodate each of your forms and handle the event of toggle within this view. Then include this via the {{view}} helper within the template of your main view.
3.Use pure js DOM handling (no {{action}} helper) and call your ember components from there.
Example of approaches 1 and 3 can be found here,
http://emberjs.jsbin.com/acUCocu/1
hbs
<script type="text/x-handlebars" data-template-name="index">
<i>using <b>{{action}}</b> helper</i>
<ul>
{{#each color in model}}
<li {{action 'test' color}}>{{color.name}}</li>
{{/each}}
</ul>
<i>using pure js DOM event handling</i>
<ul>
{{#each color in model}}
<li onclick="Ember.View.views[$(this).closest('.ember-view').attr('id')].controller.send('test2',this)">{{color.name}}</li>
{{/each}}
</ul>
</script>
js
App = Ember.Application.create();
App.Router.map(function() {
// put your routes here
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return colors;
},
actions:{
test:function(param){
alert('this is color:'+param.get('name')+" ("+param+")");
},
test2:function(elem){
alert('from pure js, clicked element: '+elem);
$(elem).css('color','red');
}
}
});
App.Color = Ember.Object.extend({
name:null
});
var colors=[];
colors.pushObject(App.Color.create({name:'red'}));
colors.pushObject(App.Color.create({name:'green'}));
colors.pushObject(App.Color.create({name:'blue'}));

Categories