I am trying to call some code after an Ember {{#each}} tag has finished looping through its items. I have seen other questions that looked similar and the answer always implemented didInsertElement on the view. This does not seem to work for me as I am trying to access html objects that are not rendered with the view because they are in the {{#each}}.
Here is what my html looks like.
<script type="text/x-handlebars" id="user">
{{#if isEditing}}
<div class="well">
{{partial 'user/edit'}}
<button {{action 'doneEditing'}} class="btn btn-default">Save</button>
<button {{action 'cancelEditing'}} class="btn btn-default">Cancel</button>
</div>
{{else}}
<button {{action 'edit'}} class="btn btn-default">Edit</button>
{{/if}}
</script>
<script type="text/x-handlebars" id="user/edit">
{{#view 'editor'}}
<div id="sList" class="btn-group-vertical" role="group">
{{#each s in model}}
<button class="btn btn-default">
{{s.theme}}
</button>
{{/each}}
</div>
{{/view}}
</script>
And my javascript
App.UserRoute = Ember.Route.extend({
model: function(params) {
return this.store.all('strength')
}
});
App.UserController = Ember.ObjectController.extend({
isEditing: false,
actions: {
edit: function(){
this.set("isEditing", true);
},
doneEditing: function(){
this.set("isEditing", false);
},
cancelEditing: function(){
this.set("isEditing", false);
}
}
});
App.EditorView = Ember.View.extend({
didInsertElement: function() {
//Do something to the button elements
}
});
When I try to run this, as soon as I hit the edit button and the partial loads, I get an error in the console after didInsertElement tried to access the button elements. It as if the elements in the div have not rendered yet. So how can I tell if the {{#each}} is done inserting elements into the html? I know this may be confusing but any and all help is appreciated.
Schedule your code in the afterRender queue to run after the contents of the view has been rendered.
App.EditorView = Ember.View.extend({
didInsertElement: function() {
Ember.run.schedule('afterRender', function() {
this.$().find('button').each(function() {
// $(this) is a button in this function
});
}.bind(this));
}
});
Related
I have two collections FoodCategory(_id,Category) and FoodInfo (_id,Category,Cat_ID,FootItem,Cost).
I want to display FootItem and Cost when a user clicks a button showing Category from FoodCategory, I have displayed button showing Category but not getting around the concept of how to retrieve data from collection when button is clicked.
File 1. ManageFoodItem.html
<template name="manageFoodItems">
<button type="button" class="btn btn-primary " id="updateNewItemBtn">Update Item</button>
<div class="updateItemPanel">
{{#each catDisplay}}
{{> manageFoodUpdateItemSection}}
{{/each}}
</div>
</template>
<template name="manageFoodUpdateItemSection">
<a class="btn btn-default expandCategory" href="#" role="button">{{Category}}</a>
<div id="categoryFoodItem">
<!--This is where I want to display FootItem when Foot Category button with Class expandCategory is clicked-->
{{FoodItem}}
</div>
</template>
ManageFoodItem.js
Template.manageFoodItems.helpers({
catDisplay: function() {
return FoodCategory.find({});
}
});
ManageFoodUpdateItemSection.js
This template is in the file ManageFootItem.html:
Template.manageFoodUpdateItemSection.events({
'click .expandCategory': function(evt, tmpl) {
evt.preventDefault();
var clikedFoodCatId = this._id;
alert(clikedFoodCatId);
Session.set("curFoodCatID", clikedFoodCatId);
return FoodInfo.find({
Cat_ID: clikedFoodCatId
});
}
});
Template.manageFoodUpdateItemSection.helpers({
footItemDisplay: function() {
var curFoodId = Session.set("curFoodCatID");
curFoodId = "jZyBxkfEAHJrdaKJ6";
}
});
footItemDisplay in helpers function can retrieve data from collection if I use for each but I want data to dispay when I click button showing {{Category}}.
You could use Session to store the current document's _id of FoodCategory and in further consequence react to click events. For example:
if (Meteor.isClient) {
Template.manageFoodUpdateItemSection.helpers({
currentFoodItem: function() {
return Session.get('catId') == this._id;
},
FoodInfo: function() {
return FoodInfo.find({"Cat_ID": Session.get('catId')});
}
});
Template.manageFoodUpdateItemSection.events({
'click .expandCategory': function() {
Session.set('catId', this._id);
}
});
}
<template name="manageFoodUpdateItemSection">
<a class="btn btn-default expandCategory" href="#" role="button">{{Category}}</a>
{{#if currentFoodItem}}
<div id="categoryFoodItem">
{{#each FoodInfo}}
{{FoodItem}}
{{/each}}
</div>
{{/if}}
</template>
I am trying to create a select box in a modal that has a list of all cars in inventory. If I enter the app from a page that has all the data loaded and open the modal it works correctly. However if I am on a route that doesn't have the data loaded, then open the modal the select options do not show. Furthermore the options will never update from that point. How do I get the proper data to load? Should not this work since I am fetching the data direct from the store?
Dms.SellDialogController = Ember.ArrayController.extend({
cars: function() {
return this.store.find('car').filterProperty('isSold', false);
}.property('model'),
selectedCar: '',
carObjects: function() {
var cars = this.get('cars').map(function(car) {
return obj = {id: car.get('id'), key: car.get('keyNumber'), label: 'KEY#:'+car.get('keyNumber') + ' - STOCK#:' + car.get('stock')+' '+car.get('year')+' '+car.get('vModel')};
});
cars.sort(function(a, b){return a.key-b.key;})
return cars;
}.property('route'),
title: 'Select the car you are selling'
});
ApplicationRoute...
...
openModal: function(modalName, model) {
this.render(modalName, {
into: 'application',
outlet: 'modal',
model: model
});
},
Action to open modal inside application template
{{action 'openModal' 'sellDialog' model}}
and the templates
<script type="text/x-handlebars" id="components/modal-dialog">
<div class='modal-overlay' {{action "closeModal" target=cntrllr}}>
<div class='modal' {{action "dngn" target=cntrllr bubbles=false}}>
<div class='modal-content'>
<div class='modal-header'>
<button type="button" class="close" aria-label="Close" {{action "closeModal" target=cntrllr}}><span aria-hidden="true">×</span></button>
<h4 class="modal-title">{{title}}</h4>
</div>
{{yield}}
</div>
</div>
</div>
</script>
<script type="text/x-handlebars" data-template-name="sellDialog">
{{#modal-dialog title=title cntrllr=controller model=model}}
<div class="modal-body">
<span class='pull-left'>Key Number:
{{view "select" content=carObjects optionValuePath="content.id" optionLabelPath="content.label" selection=selectedCar}}
</span>
</div>
<div class="modal-footer">
<button {{action "modalAction" controller "sell" selectedCar.id}}>Sell</button>
<button {{action "closeModal"}}>Cancel</button>
</div>
{{/modal-dialog}}
</script>
UPDATE 2015/5/4:
I have a hack to make it work for now. I added a cars property in the application route and I am getting it in SellDialogController. This looks like a bug to me. I will make a jsFiddle when I get some time and check it further before issuing a bug report.
try using setupController on the Application Route, since setupController is always called.
import Ember from 'ember';
export default Ember.Route.extend({
model: Ember.RSVP.hash({
optionsForSelect: function() {
// fetch your select data here
},
otherData: function() {
// get your regular model data here
}
}),
setupController: function(controller, model) {
this.controllerFor('sellDialog').set('model', model.optionsForSelect);
this.controller.set('model', model.otherData);
}
});
So, Basically i'm new to meteor(0.8.2) and trying to create a basic app having two templates(addnewPlace and Map) and a single button. What i need to get is that, when i click on "Add new Place" button, template "addNewPlace" should be loaded in body or else template "Map" should be loaded. Help will be appreciated :)
My html code:
<body>
{{> menu}}
{{> body}}
</body>
<template name="body">
{{#if isTrue}}
{{> addnewPlace}}// tested this template individually, it works.
{{else}}
{{> maps}} // tested this template individually, it works too.
{{/if}}
</template>
<template name="menu">
<h1>Bank Innovation Map</h1>
<input type="button" value="Add new Place">
</template>
My js code:
Template.body.isTrue = true;
Template.menu.events({
'click input': function(){
//load a new template
console.log("You pressed the addNewplace button");//this fn is called properly
Template.body.isTrue = true;
}
});
Well first of all you obviously aren't changing anything in the click event (true before, true after). But also if you did, I think you might be better off using a session variable for this, to maintain reactivity.
Session.setDefault('showAddNewPlace', false)
Template.body.isTrue = function() { Session.get('showAddNewPlace'); }
Template.menu.events({
'click input': function(){
//load a new template
console.log("You pressed the addNewplace button");//this fn is called properly
Session.set('showAddNewPlace', true)
}
});
Meteor 0.8.2 comes in with the dynamic template include feature. Just set a session variable value on click event and you would like to use the template name on the event.
Session.setDefault('myTemplate', 'DefaultTemplateName');
"click input": function (event) {
Session.set("myTemplate", 'template_name');
}
You can now write this:
<body>
{{> menu}}
{{> body}}
</body>
<template name="body">
{{> UI.dynamic template=myTemplate}}
</template>
<template name="menu">
<h1>Bank Innovation Map</h1>
<input type="button" value="Add new Place">
</template>
You may like to take a look at this article for the reference:
https://www.discovermeteor.com/blog/blaze-dynamic-template-includes/
I'm new to ember I am trying to append a template to another and it seems to work but it raises an error, can you please explain why?
The error:
Assertion failed: You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead
This is the code in app.js
App.NewStickie = Ember.View.extend({
click: function(evt){
var stickie = Ember.View.create({
templateName: 'stickie',
content: 'write your notes here'
});
stickie.appendTo('#stickies');
}
});
These are the contents of index.html
<script type="text/x-handlebars">
{{#view App.NewStickie}}
<button type="button" class="btn btn-success">
New
</button>
{{/view}}
{{outlet}}
</script>
<script type="text/x-handlebars" id="index">
<div id="stickies">
{{#each item in model}}
<div class="stickie" contenteditable="true">
{{#view App.DeleteStickie}}
<span class="glyphicon glyphicon-trash"></span>
{{/view}}
<div contenteditable="true">
{{item.content}}
</div>
</div>
{{/each}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="stickie">
<div class="stickie">
{{#view App.DeleteStickie}}
<span class="glyphicon glyphicon-trash"></span>
{{/view}}
<div contenteditable="true">
{{view.content}}
</div>
</div>
</script>
Each view in ember have a template, for example:
foo_view.js
App.FooView = Ember.View.extend({
templateName: 'foo'
})
foo template
<script type="text/x-handlebars" data-template-name="index">
<div id=myFooView>Foo</div>
</script>
You are trying to insert a view inside of other in that way:
App.BarView.create().appendTo('#myFooView')
This isn't allowed. You can use the {{view}} handlebars helper to render a view inside other like that:
foo template
<script type="text/x-handlebars" data-template-name="index">
<div id=myFooView>
Foo
{{view App.BarView}}
</div>
</script>
But I think that you want this working dynamically. So you can use the ContainerView, like described by the error message:
App.StickiesView = Ember.ContainerView.extend({
click: function() {
var stickie = Ember.View.create({
templateName: 'stickie',
content: 'write your notes here'
});
this.pushObject(stickie);
}
})
I see in your code a lot of views with the click event, ember encourage you to use actions, this give more flexibility, error/loading handling etc. I think is a good idea to use it.
I hope it helps
You should probably read this guide that explains that ContainerView is. Also, I don't think it's necessary to create another View to append a template to another template.
Essentially I have a list of objects, and the user is able to add new ones by typing into a textbox. As the user types, the new object appears. However, when the user clicks save, the object disappears from the listing. It is successfully saved to the database (Ruby on Rails/SQLite) so it appears on a full refresh. Why is it doing this, and how can I get it to stay on the screen when the user presses submit?
Here is some relevant code:
index.hbs
<div class="messages">
{{#each userhashtag in controller}}
{{render "userhashtag" userhashtag}}
{{/each}}
{{#link-to 'userhashtags.new'}} Add Hashtag{{/link-to}}
</div>
{{outlet}}
show.hbs
{{userhashtag.name}} <button class="btn btn-dancer" type="submit" {{action "destroy"}}>Remove</button><br>
new.hbs
<form role="form">
<fieldset>
<div class="form-group">
{{view Ember.TextField valueBinding='name' class='form-control' name='name' viewName='nameField'}}
</div>
<div class="btn-group">
<button type="submit" {{action "save"}} class="btn btn-success">Submit</button>
</div>
route
App.UserhashtagsNewRoute = Ember.Route.extend({
model: function(){
return this.store.createRecord('userhashtag');
},
setupController: function(controller, model){
controller.set('model', model);
},
renderTemplate: function() {
this.render('app/templates/userhashtags/new');
},
actions: {
save: function(){
return this.controller.get('model').save().then(function(){
this.transitionTo('userhashtags');
}.bind(this));
}
}
});
Make sure that you are manually pushing the new model into your Array collection (not sure how you're managing the collection). I'd suggest moving the #save action into a controller where you manage the list of objects.
// assuming "list" is some reference to your collection list within your controller
save: function() {
this.get('userhashtag').save().then(function(_model){
list.pushObject(_model);