Sort array based on startDate - meteor

I'm trying to sort an array and not having much luck. If I remove the helper I print out the all the qualifications in the order they went into the database. I would like to display them chronologically based on their startDate.
Path: dbExample
"profile": {
"CV": {
"education": [
{
"qualification": "Arts Degree",
"startDate": "2009-01-01T00:00:00.000Z",
"endDate": "2013-12-01T00:00:00.000Z"
},
{
"qualification": "Science Degree",
"startDate": "2007-01-01T00:00:00.000Z",
"endDate": "2008-12-01T00:00:00.000Z"
}
]
}
}
Path: education.html
<template name="education">
{{#each educationHistory}}
<div class="box">
<p class="title">{{qualification}}</p>
<p class="dates">{{startDate}} - {{endDate}}</p>
</div>
{{/each}}
</template>
Path: education.js
Template.education.helpers({
educationHistory: function () {
return Meteor.users.find({}, {sort: {"startDate": 1}});
}
});
Path: Schema.js
Schema.Education = new SimpleSchema({
qualification: {
type: String,
optional: true
},
startDate: {
type: Date,
optional: true
},
endDate: {
type: Date,
optional: true
}
});
Schema.CV = new SimpleSchema({
education: {
type: [Schema.Education],
optional: true
}
});

This is a little hard to follow because I don't know the context of the template or which user's education history to use. Here are a couple of solution ideas:
solution 1
Template.education.helpers({
educationHistory: function () {
// replace Meteor.user() with Meteor.users.findOne(someId) or something
const { education } = Meteor.user().profile.CV;
return _.sortBy(education, e => e.startDate);
},
});
This returns an array of education objects, sorted by startDate.
solution 2
If the template already has an educationHistory without the helper (based on your comments below), then you can replace the educationHistory helper with this:
Template.education.helpers({
sortByStartDate: function (education) {
return _.sortBy(education, e => e.startDate);
},
});
Then in your template:
<template name="education">
{{#each sortByStartDate educationHistory}}
<div class="box">
<p class="title">{{qualification}}</p>
<p class="dates">{{startDate}} - {{endDate}}</p>
</div>
{{/each}}
</template>

Related

Use of "#each" with multiple variables in Handlebars

How to "select" a value with "this" when there are multiple #each in Handelbars ?
{{#each marqueauction}}
{{#each modelauction}}
<div class="results__container--box">
{{this.marqueauction}}
{{this.modelauction}}
</div>
{{else}}
<div class="results__container--box">
<p>Aucun résultat d'enchères n'est disponible pour ce modèle.</p>
</div>
{{/each}}
{{/each}}
EDIT: I want to call my MongoDB database with mongoose and display results in a box container. For that, I loop through my results array.
My Mongoose model:
const DemocarauctionSchema = new Schema({
objectID: {
type: Number
},
cars_getroute: {
type: String
},
gm_url: {
type: String
},
"results": { type: [{
marque: {
type: String
},
model: {
type: String
},
model_year: {
type: String
},
price_str: {
type: String
},
prince_int: {
type: Number
},
price_currency: {
type: String
},
sold: {
type: Boolean
},
auction_house: {
type: String
},
auction_country: {
type: String
},
auction_date: {
type: String
},
auction_datetime: {
type: String
},
auction_url: {
type: String
},
image_urls: {
type: String
},
price_int_eu: {
type: Number
},
}]}
}
I loop through the array in Express/Node:
const [democarauctions] = result;
let marqueauction = [];
for (let i = 0; i < democarauctions.results.length; i++) {
marqueauction.push(democarauctions.results[i].marque)
}
let modelauction = [];
for (let i = 0; i < democarauctions.results.length; i++) {
modelauction.push(democarauctions.results[i].model)
}
...
And I call the results array in my "res.render":
res.render(demo, {
results: democarauctions.results,
marqueauction: marqueauction,
modelauction: modelauction,
modelyearauction: modelyearauction,
etc.})
Now I'd like to render on my HTML multiple box for each result, with marqueauction, modelauction, modelyearauction in each one. I use handlebars.
It is best to avoid this and instead use named block parameters :
{{#each marqueauction as |marque|}}
{{#each modelauction as |model|}}
<div class="results__container--box">
{{marque}}
{{model}}
</div>
{{else}}
<div class="results__container--box">
<p>Aucun résultat d'enchères n'est disponible pour ce modèle.</p>
</div>
{{/each}}
{{/each}}
I'm not sure why you are breaking apart the original collection into multiple collections and then trying to combine them again in the presentation. Just use the results directly.
EDIT: based on your updated question:
{{#each results as |auction|}}
<div class="results__container--box">
{{auction.marque}}
{{auction.model}}
</div>
{{else}}
<div class="results__container--box">
<p>Aucun résultat d'enchères n'est disponible pour ce modèle.</p>
</div>
{{/each}}

Using package aslagle:reactive-table with X-editable

I'm using reactive table package from aslagle in my app and I want to create in-line editing, I searched and I found that there's x-editable package for Meteor, so how can I use aslagle:reactive-table package with workman:x-editable-reactive-template package?
I tried this:
Reactive-Table settings:
tableSettings: function () {
return {
collection: fLogCollection,
rowsPerPage: 10,
showFilter: true,
fields: [
{ key: 'name', label: 'Name'},
{ key: 'amount',
label: 'Amount',
tmpl: Template.xEditableAmount
},
{ key: 'cashFrom', label: 'Cash From'},
{ key: 'dateIs', label: 'Date', sortOrder: 0, sortDirection: 'descending'},
{ key: 'controls', label: 'Controls', fn: function () {
return new Spacebars.SafeString(
"<button class='editFlog'><span class='glyphicon glyphicon-pencil'></span> </button>"+
"<button class='delete'><span class='glyphicon glyphicon-remove'></span> </button>"
); } },
{ key: 'createdAt', label: 'createdAt', hidden: true },
],
};
},
xEditableAmount template:
<template name="xEditableAmount">
{{amount}}
</template>
This code to get the x-editable rendered:
Template.fLog.onRendered(function() {
this.$('.editable').editable({
success: function (response, newValue) {
if(response.status == 'error') return response.msg; //msg will be shown in editable form
else Meteor.call('flog.edit2', this._id, newValue);
},
});
});
I succeeded in making x-editable render but
I failed at getting the field updated with the new value in collection...
You can inject templates into fields which makes it convenient to add almost anything you want.
Template helper:
tableSettings: function() {
return {
collection: foo,
fields: [
{
key: 'foo_1',
label: 'Foo 1',
tmpl: Template.foo1,
},
{
key: 'foo_2',
label: 'Foo 2',
tmpl: Template.foo2,
},
{
key: 'foo_2',
label: 'Foo 2',
tmpl: Template.foo2,
}
]
};
}
In foo2 helper (copied directly from workman/x-editable-reactive-template atmosphere page):
Template.foo2.helpers({
onSuccess: function () {
var id = this._id;
return function (res, val) {
MyColl.update({ _id: id }, { $set: { prop: val } });
}
}
});
In your Templates:
<template name='table>
{{> reactiveTable settings=tableSettings}}`
</template>
<template name='foo1'>
<!-- Any html (below pasted from docs (link at bottom of post)-->
superuser
</template>
<template name='foo2'>
{{> xEditable type="text" success=onSuccess placement="right" }} <!-- put your workman:x-editable-reactive-template here -->
</template>
This should get you pointed in the right direction.
https://vitalets.github.io/x-editable/docs.html

How to add user id information in the schema and also hide form autoforms?

I am learning the ropes of Meteor and kind of lost here. I am using collections2, autoform for building my application. I want to store the collection along with user id information. So that when we retrieve the collection from the server, I want to show only the ones the user created not everything else. here is the schema.
ExercisesSchema = new SimpleSchema({
"name": {
type: String,
label: 'Name'
},
"workout.$.weight": {
type: String,
label: 'Weight'
},
"workout.$.reps": {
type: String,
label: 'Reps'
},
"notes": {
type: String,
label: 'Notes',
optional: true
}
});
on the server side I want to show only the workouts created by the user
Meteor.publish('exercises', function () {
return Exercises.find({owner: this.userId});
});
When I added the user id to the schema, it shows up in the autoform, I am not sure how to hide it, if I hide it, then possibly I can use hooks in the autoform to add the values?
In the schema you can define the ownerId as type: "hidden"
schema.js
ExercisesSchema = new SimpleSchema({
"name": {
type: String,
label: 'Name'
},
"ownerId": {
type: String,
autoform: {
type: "hidden",
}
},
"workout": {
//not sure if you need this, you didn't have it in your
type: [Object],
defaultValue: []
},
"workout.$.weight": {
type: String,
label: 'Weight'
},
"workout.$.reps": {
type: String,
label: 'Reps'
},
"notes": {
type: String,
label: 'Notes',
optional: true
}
});
And populate it with the hooks as you said.
autoFormHooks.js
AutoForm.hooks({
exerciseForm: {
formToDoc: function(doc) {
doc.ownerId = Meteor.userId();
return doc
},
}
});
An alternative to using hooks would be to use a quickFields inside of your autoForm for each field that you want to set in the doc, including ownerId. With this solution you would set the value of ownerId to currentUser.
{{#autoForm collection="Exercises" id="exerciseForm" type="insert"}}
<fieldset>
<legend>Add an Exercise</legend>
{{> afQuickField name='name'}}
{{> afQuickField name='notes'}}
{{> afQuickField name='ownerId' value=currentUserId}}
{{> afQuickField name='workout'}}
</fieldset>
<button type="submit" class="btn btn-primary">Insert</button>
{{/autoForm}}
template.js
Template.formTemplate.helpers({
currentUserId: function () {
return Meteor.userId();
}
});
You could try the before hook approach:
ExercisesSchema = new SimpleSchema({
...
"ownerId": {
type: String,
autoform: {
type: "hidden",
}
},
...
});
In your template:
{{#autoForm collection="Exercises" id="exerciseForm" type="insert"}}
<fieldset>
<legend>Add an Exercise</legend>
{{> afQuickField name='name'}}
{{> afQuickField name='notes'}}
<!-- Notice I've removed the ownerId from here. Will be added before saving to collection -->
{{> afQuickField name='workout'}}
</fieldset>
<button type="submit" class="btn btn-primary">Insert</button>
{{/autoForm}}
Then your autoform.js
var addUserHook = {
before: {
insert: function(doc) {
if(Meteor.userId()){
doc.ownerId = Meteor.userId();
}
return doc;
}
}
}
AutoForm.addHooks('exerciseForm', addUserHook);
The above adds the ownerId on the fly just when about to save to collection.
As stated in the docs on atmospherejs.com/aldeed/autoform:
For example, you might want to add the current user's ID to a
document before it is inserted. You can use "before", "formToDoc", or
"formToModifier" hooks to do this.

Meteor collection2 field in $unset list

I have a simpleSchema:
imageUrl: {
type: Object,
optional: true,
autoValue: function() {
if (Meteor.isClient) return;
var imageField = this.field('imageId');
if (!imageField.isSet){
this.unset();
} else {
var imageObj = MealsImages.findOne(imageField.value);
if (imageObj){
return {thumb: imageObj.S3Url('thumb'), big: imageObj.S3Url('big')};
}
}
},
autoform: {
label: false,
type: 'hidden',
afFieldInput: {
type: "hidden"
}
}
},
For some reason, when I update the record this field always appears in $unset array:
Meteor.methods({
mealUpsert: function(doc, mealId) {
check(doc, Meals.simpleSchema());
console.log('test7');
console.log(doc);
if (mealId){
Meals.update({_id: mealId}, doc);
} else {
mealId = Meals.insert(doc);
}
return false;
}
});
Will print:
I20150830-21:49:39.560(-4)? { '$set':
...
I20150830-21:49:39.562(-4)? '$unset':
I20150830-21:49:39.562(-4)? { imageUrl: '',
...
I'm using autoform:
<template name="mealUpdateForm">
<div class="meal-content">
{{> quickForm collection="Meals" doc=this id="mealUpdateForm" meteormethod="mealUpsert" type="method-update"}}
</div>
</template>
And will never be updated or set. Any clue why field could appear in $unset list?
I think I've figured this out - you have a this.unset() in your autoValue for imageUrl. This is called whenever you omit imageId from the modifier, even if it is already present in a document you are modifying!

Ember-data loading async and order results according with property

I'm learning about ember/ember-data and would like to fetch some data from server and order it.
My json data is something like
{
'ninjas': [
{ id: '1', name: 'Ninja 1', age: 23},
{ id: '2', name: 'Ninja 2', age: 27},
{ id: '3', name: 'Ninja 3', age: 22}
],
'clans': [
{ id: '1566', title: 'Foot Clan', ninja_ids: ['1', '2']},
{ id: '8941', title: 'Hand Clan', ninja_ids: ['3']}
]
}
The templates are
<script type="text/x-handlebars" data-template-name="clans">
<div>Clans</div>
<ul>
{{#each controller}}
<li>
{{#link-to 'clan' this}}{{title}}{{/link-to}}
</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="clan">
<div>{{title}}</div>
{{#each fetchedNinjas}}
<ul>
<li>{{fetchedNinjas}}</li>
</ul>
{{/each}}
</script>
Here is the basic App script:
var App = Ember.Application.create();
App.AplicationStore = DS.Store.extend({
revision: 12,
adapter: DS.RESTAdapter.create({})
});
App.Router.map(function() {
this.resource('ninjas');
this.resource('clans');
this.resource('clan', {path: 'clans/:clan_id'});
});
The ninja script is here:
App.Ninja = DS.Model.extend({
name: DS.attr('string'),
age: DS.attr('number'),
clans: DS.hasMany('clan')
});
App.NinjasRoute = Ember.Route.extend({
model: function (params, transition, queryParams) {
return this.store.find('ninja');
}
});
Here is the Clan Model, ClansRoute, ClanRoute
App.Clan = DS.Model.extend({
title: DS.attr('string'),
ninjas: DS.hasMany('ninja', {async: true})
});
App.ClansRoute = Ember.Route.extend({
model: function (params, transition, queryParams) {
return this.store.find('clan');
}
});
App.ClanRoute = Ember.Route.extend({
model: function (params, transition, queryParams) {
return this.store.find('clan', params.clan_id);
}
});
I think that I should get the related ninja data on ClanController and then order it, but I don't know how to proceed.
App.ClanController = Ember.ObjectController.extend({
fetchedNinjas: function () {
//should I use a promise here?
}.property('ninjas')
});

Resources