Lets say I have this 'Model'
var lists = [
{
title: 'Default title',
image: '/img/default.jpeg',
section: [
{ name: 'Default Name',
description: 'Default Description'
}
],
activity: ['default']
}
];
Here is the view templates
<template name="main_list_view">
{{#each list.section}}
{{> section}}
{{/each}}
<a id="addSection" href='#'>Add Section</a>
</template>
<template name="section">
<li>{{section.name}}</li>
<li>{{section.description}}</li>
<a class="deleteSection" href='#'>Delete Section</a>
</template>
I need help w the logic for add more sections and remove a specific section from the colection.
I have checked mongoDB and looks like I have to use something like addToset and $unset for update the model, but I really only want to remove them from the view, cause I want the default model to remain the same always.
So how I remove and add Templates to the view when the user clicks Addcontent, and remove the specific view when the user clicks remove ? is there a Meteor way to do it ? So a user clicks addContent and a new section template is rendered or removed if clicks remove.
Removing one should be simple enough. First, it might help to add the id of the section in your delete link:
<a data-id="{{section._id}}" class="deleteSection" href='#'>Delete Section</a>
Template.section.events({
'click a.deleteSection': function(evt) {
Sections.remove($(evt.target).data('id'));
}
});
Adding one is a different story, because it depends on exactly what you want to happen when you click the addSection link. Does that link render a form that creates a new Section on submission? Or does the handler to that link create a Section object and fill in the values?
Edit
It was pointed out that Sections is not a collection. I should've seen that. Making it into a collection would be an obvious way to deal with that. So instead of:
{{#each list.section}}
{{> section}}
{{/each}}
You'd have:
{{#each sections list._id}}
{{> section}}
{{/each}}
And in your js file:
Template.main_list_view.helpers({
sections: function(list_id) {
return Sections.find({ list_id: list_id });
}
});
Alternatively, you could move the "section" template up to the parent and then you could add the list_id as a data attribute on the link::
{{#each list.section}}
<li>{{name}}</li>
<li>{{description}}</li>
<a data-id="{{list._id}}" data-name="{{name}}" data-description="{{description}}" class="deleteSection" href="#">Delete Section</a>
{{/each}}
Then in your js file:
Template.section.events({
'click a.deleteSection': function(evt) {
var list = Lists.find($(evt.target).data('id'));
var section = { name: $(evt.target).data('name'), description: $(evt.target).data('description') };
sections = list.sections;
sections.splice(sections.indexOf(section), 1);
Lists.update(list._id, $set: { sections: sections });
}
});
Related
So I have two collections, appliers & profiles,
appliers = {_id,idAppliersProfile}
&
profile = {_id,profilename}
So my question is if I do an #each for appliers, how do I access profile collection to get the profile instead of just the id?
Thanks.
Assuming both sets of docs are published to the client, one solution looks something like this:
html
<template name="myTemplate">
{{#each appliers}}
{{#with getProfile idAppliersProfile}}
<div>{{profilename}}</div>
{{/with}}
{{/each}}
</template>
js
Template.myTemplate.helpers({
appliers: function () {
return appliers.find();
},
getProfile: function (id) {
return profile.findOne(id);
}
});
Iron Router cannot find a path that I'm pretty sure is defined correctly. The path name shows up as valid and exists in my meteor shell, but it returns as "undefined" in my Chrome console. Here's the template declaration:
<template name="vidPreview">
<div class="videoPreview">
<h2>{{title}}</h2>
Play
<p>Created At: {{createdAt}}</p>
{{#if isLive}}
<p>LIVE</p>
{{/if}}
<p>Viewers: {{uniqueViewers}}</p>
<p>Views: {{views}}</p>
<p>Location: {{location}}</p>
<ul>
{{#each genres}}
<li><p>{{this}}</p></li>
{{/each}}
</ul>
<p>Created by: {{creator}}</p>
</div>
</template>
And here's the route declaration:
Router.route('/video/:_id',{
name: 'singleVideo',
template: 'singleVideo',
layoutTemplate: 'singleVideo',
data: function(){
var currentVideo = this.params._id;
return Videos.findOne({ _id: currentVideo });
},
action: function(){
this.render('singleVideo');
}
});
There are no helpers operating on the vidPreview template. The data context is that of an individual Video object, and this template gets placed multiple times into a parent template. Help is greatly appreciated.
I thought the route name parameter in pathFor was positional, i.e.
{{pathFor 'singleVideo' _id=this._id }}
"We can pass data, query and hash options to the pathFor helper."
Try:
{{pathFor route='singleVideo' data={ _id: this._id} }}
I wrote a little angular app. I've got an array of menu items which I print in my template:
<nav id="menu">
<ul>
<li ng-repeat="i in menuItems"
ui-sref="{{ i | removeSpacesThenLowercase }}"
ui-sref-active="active">{{ i }}</li>
</ul>
</nav>
And in my app.js I declared my states using ui-router like:
.state('camera', {
url: '/selection',
templateUrl: '/views/selection.html',
uiShade: 'light back',
back: 'intro'
})
Internal URLs work just fine, but what if I want to do this?
.state('facebook', {
url: 'https://www.facebook.com/'
})
This obviously doesn't work. What would be the best approach to have some external (absolute) links in my template without having two separate arrays?
Ui-sref refers to a state. Your views are states. Externals sites aren't states, it's just some outside links.
I suggest you to refactor your menu generator to handle different type of menu entries :
state based link (link generated through ui-sref)
standard link (link generated through href, for external links, emails, etc)
Then you just have to populate menuItems with an array of different objects
I fixed this in my application using ng-if.
Example menu items:
$scope.navItems = [{
id: 1,
title: 'Internal Link',
href: null,
sref: 'internal-state'
},
{
id: 2,
title: 'External Link',
href: 'https:/google.co.uk',
sref: null
}];
Then in the HTML I set the ng-repeat on the <li> but include an <a> for href and one for sref, each with an ng-if.
<li ng-repeat="item in navItems">
<a ng-if="item.sref" ui-sref="{{item.sref}}">{{ item.title }}</a>
<a ng-if="item.href" href="{{item.href}}">{{ item.title }}</a>
</li>
I fixed this by creating a second array for the external links and an ng-click function.
$scope.elink = function(element) {
if (confirm("You're leaving the app, are you sure?")) {
window.location = element;
}
};
I can't get a the 'show' page of an instance of a model to display its data.
Here's the template that won't show its data:
<template name="priority">
<h1>Priority: {{title}}</h1>
</template>
It's very simple in and of itself, yet I can't get title to display. Iron:router does the job of directing us to this page with the following code:
Router.route('/priority/:_id', function(){
var priority = this.params._id;
this.render('priority', {
data: function(priority){
Meteor.call('showPriority', priority, function(error){
if (error) {
console.log("An error has occured: " + error);
}
})
}
})
}, {
name: 'priority.show'
});
The Meteor.method is very simple, it just queries for the variable priority:
'showPriority': function(priority) {
return Priorities.findOne({_id: priority});
}
The view which carries the href is here:
<template name="priorityList">
<ul class="table-view">
{{#each this}}
<li class="table-view-cell">
{{title}}
<span class="pull-right icon icon-edit"></span>
</li>
{{/each}}
</ul>
</template>
Note that this view shows a list of all priorities. When I inspect the href, all the paths are being dynamically generated with an _id:
<a href="/priority/yYihyZmZ2xkAso7i5">...
Oh, and I should mention, that I also tried to use the waitOn method, since I thought I might be loading the template before the data, but that didn't help either...
Router.configure({
...
waitOn: function(){
return Meteor.subscribe('priorities');
}
});
So much code, just to show what's going on!
What's the deal here? Why won't my "show" template give me any data?
Change you route to this.
Router.map(function () {
this.route('priority', {
path: '/priority/:_id',
waitOn: function(){
return Meteor.subscribe('priorities',this.params._id);
},
data: function(){
if(this.ready()){
return Priorities.findOne({_id: this.params._id});
}else{
this.render('loading') //if data not ready we render some loading template
}
}
});
});
You don't need to make a Meteor.call, for the find(); instead to everything on the data:function()
The above is just an example so you can get the idea, but it should work since you are expecting _id:priority and _id:this.params._id its the same.
Just be sure you have the autopublish package removed.
and have the subscriptions/publish in order.
Meteor.publish('Menu', function(){
return Priorities.find();
});
I am still trying to understand how to properly structure an ember.js application. So, this may be a systemic issue with the way I am trying to solve this. That being said, I am going to try asking the same question a couple different ways ...
In the code example below, when a record is created, how can I get it to be added to the list with the isEditing property set to true?
Can I access to a specific object controller from its array controller?
Each task has a view state and an edit state. When a new task is created, how can I have it initially appear in the edit state?
App.TasksController = Ember.ArrayController.extend({
actions: {
createTask: function(){
var task = this.store.createRecord('task');
task.save();
}
}
});
App.TaskController = Ember.ObjectController.extend({
isEditing: false,
actions: {
toggleEditing: function(task) {
if(this.isEditing){
task.save();
}
this.set('isEditing', ! this.isEditing );
}
}
});
<script type="text/x-handlebars" data-template-name="tasks">
<ul>
{{#each task in controller}}
{{render "task" task}}
{{/each}}
<li {{action "createTask"}} >
New Task
</li>
</ul>
</script>
<script type="text/x-handlebars" data-template-name="task">
<li {{action "toggleEditing" task on="doubleClick"}} >
{{#if isEditing }}
{{textarea value=title cols="80" rows="6"}}
{{else}}
{{title}}
{{/if}}
</li>
</script>
Set the property on the model.
You don't have to define the property as an attr on the model (which means it won't send it up to the server on save etc), but you can set the property on the model.
Or you can do it based on the currentState of the model. (click go to orders, then add orders)
http://emberjs.jsbin.com/AvOYIwE/4/edit
App.OrderController = Em.ObjectController.extend({
_editing: false,
editing: function(){
return this.get('_editing') || (this.get('model.currentState.stateName') == 'root.loaded.created.uncommitted');
}.property('model.currentState.stateName', '_editing'),
actions: {
stopEditing: function(){
// blow away the computed property and just set it to true
this.set('editing', false);
},
startEditing: function(){
this.set('editing', true);
},
}
});