Callback after iteration is completed in meteor template - mongodb

Using meteorjs and its templating solution, I need to execute a JavaScript function (as part of callback function), right after the template and the loop to render a dynamic elements (reading from mongodb) is complete.
What is the right approach in meteorjs for this matter?

To me it sounds like the rendered callback would do the job.
<template name="main">
{{> renderCollection}}
</template>
<template name="renderCollection">
{{#each theCursor}}
{{someField}}
{{/each}}
</template>
Template.renderCollection.rendered = function(){
console.log("The collection has just been rendered!")
}

Related

How can I inject a Vuetify form from a database into a template?

Apologies if this has been answered elsewhere, I have searched but not found anything as of yet.
I have a v-form stored in a database that I wish to pull back and display on a page. However, when I do so the form is not being rendered correctly. It remains as Vuetify template code and is not converted to HTML.
The form looks like this:
<v-form>
<v-container>
<v-row>
<v-col>
<div class="text-h4">Form 1</div>
</v-col>
</v-row>
<v-row>
<v-col
cols="12"
md="6"
>
<v-text-field
:counter="255"
label="Customer ID"
required
></v-text-field>
</v-col>
<v-col
cols="12"
md="6"
>
<v-text-field
label="Amount"
></v-text-field>
</v-col>
<v-col class="text-right">
<v-btn
#click="submitForm"
>
Submit
</v-btn>
</v-col>
</v-row>
</v-container>
</v-form>
I did come across a render function, but I've either not used it correctly or it is not have the desired effect - I'm a newbie at this so it may well be something simple!
The above form is pulled back from the database using axios, and the request happens in the created() function on the page where I wish to display it, using mapGetters() to grab it from the store and v-html in a v-card to show it.
Any help on this would be much appreciated.
Thanks for your time people!
How can I inject a Vuetify form from a database into a template?
You can't.
v-html docs
Updates the element’s innerHTML. Note that the contents are inserted as plain HTML - they will not be compiled as Vue templates. If you find yourself trying to compose templates using v-html, try to rethink the solution by using components instead
Another note from docs
Note that you cannot use v-html to compose template partials, because Vue is not a string-based templating engine. Instead, components are preferred as the fundamental unit for UI reuse and composition.
So in short, you cannot insert any partial template into a template of a component at runtime.
But you can create component at runtime and use it as dynamic component
const vm = new Vue({
el: '#app',
data() {
return {
downloadedTemplate: '<div> Hello </div>', // pretend this was downloaded from the server
}
},
computed: {
myDynamicComponent() {
return Vue.component('myDynamicComponent', {
template: this.downloadedTemplate
})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<component :is="myDynamicComponent" />
</div>
Note that to do this, you must use Vue distribution which includes the template compiler
I don`t know about your particular use case, but unless you are working with tens of different forms, storing templates in database sounds like a sub-optimal strategy - a lot of unnecessary work and hard to mainain

{{#each pages}} not working in Assemble 0.6.0/Gulp-Assemble

I've got my pages correctly pulling in partials and sources but I can't seem to get something resembling a navigation to work using the {{#each pages}} logic.
I am trying to gather up all my pages and output them as a unordered list.
{{#each pages }}
<li>{{basename }}</li>
{{/each}}
I thought I was following 0.6.0 methodology:
gulp.task('assemble', function () {
assemble.layouts('./templates/layouts/*.hbs');
assemble.option({
layout: 'default'
});
gulp.src('./src/hbs/components/**/*.hbs')
.pipe(gulpAssemble(assemble))
.pipe(prettify())
.pipe(extname())
.pipe(gulp.dest('./dist'));
});
Again, everything else seems to work. I don't understand where the "pages" object that #each is iterating over comes from. I've used {{#log this}} and I can see the the "basename" object but I don't see the "name" object.

How to combine two collections objects to one table while looping over all objects in Meteor.js?

I'm working on the simple Meteor Chat application. I have two different collections, textMessages and FS.images. I need to display those element based on time in one flow. Now I submit them both apart from each other and can't figure the way, while looping over them using #each handler.
Template code :
<ul class="list-group">
{{#each messages}}
<li class="list-group-item">
<span class="badge">x</span>
UserN: {{text}}
</li>
{{/each}}
</ul>
<ul class="list-group">
{{#each showImages}}
{{#unless this.isUploaded}}
{{> FS.UploadProgressBar bootstrap=true}}
{{/unless}}
{{> imageItem}}
{{/each}}
</ul>
You can create a helper in the template that would combine both collections results and sort them by date if each user has set of images and text.
If each message has a set of images you can use this package for creating helper for the collection in such a way you can get the set of images for a certain message.
meteor-collection-helpers

Is it possible to implement dynamic form input rows (adding new row by clicking on Add) with Handlebars and Meteor?

I'm getting my hands dirty with Meteor, and I wanted to port this AngularJS app (http://simplydo.com/projector/) over as an exercise.
I'm having difficulty implementing adding dynamic input form rows to sections using Handlebars, and I've found no documentation anywhere that documents if this possible. It's a snap in Angular using ng-repeat, but I want to confirm if this is something that is possible in Handlebars or whether I need to use Jquery in order to achieve this.
Thanks in advance.
It's just as easy in Meteor
all you have to do is repeat the rows with {{#each rowData}} and have a button that adds a document to the collection. Here is an example:
In this template the rows for a page are shown. In order to add a row, the user has to click on the add image. The template is :
<template name="page">
{{#with page}}
<h3>{{title}}</h3>
{{#each rows}}
<div class="row-fluid page-row {{#if isSelected this}}selected-row{{/if}}">
... page content here
</div>
{{/each}}
{{/with}}
<div class="btn-toolbar">
<div class="pull-right">
<a id="add-row" href="#" data-toggle="tooltip" title="{{lbl 'add-page'}}">
<img src="/images/add.png" class="asset-icon"/>
</a>
<img src="/images/separator.png" class="asset-icon"/>
<a id="delete-row" href="#" data-toggle="tooltip" title="{{lbl 'delete-page'}}">
<img src="/images/delete.png" class="asset-icon"/>
</a>
</div>
</div>
</template>
the helpers for this template are:
Template.page.page = function () {
return Session.get("selected-page");
}
in order to add a page the click event for the add button is implemented:
"click #add-row": function (evt, template) {
var page = Session.get("selected-page");
Pages.update({_id: page._id}, ... add a new row here ...)
}
because the whole thing is reactive, the list of rows will redraw after the update on the Pages collection.

how can I use the same template multiple times on meteor.js

I just started use meteor about a week ago, and I'm trying to write my first app for logging time for a project.
At the end of the day users can go in and log their hours with a single row consisting of 2 drop down select menus. First is the clients drop down. then based on that client (using Session) the 2nd drop down for client projects will auto-populate, and finally allowing you to enter your hours in a text input.
I have this working, but I also need to implement a button so you can add multiple rows at once. Sort of like jQuery Clone() in case the user worked on different clients or client projects.
I tried to re-render the row once newRow is clicked, but then the second row manipulates the first row because I'm assuming they're both referencing the same template.
To simplify? 1) How do I duplicate the below the last one, and 2) How do I use the same template for 1 or more rows and have them not affect each other?
Any thoughts/help is welcome
<form id="add_time">
<template name="row">
<ul>
{{> clientsDD}}
{{> projectsDD}}
{{> hoursAndTasks}}
</ul>
</template>
<p>Add another row
<input type="submit" id="submit_hours" value="Submit"/>
</form>
Template.clientsDD.clients = function() {
return Clients.find({});
}
Template.projectsDD.projects = function(event) {
return Projects.find({"client.clientId" : Session.get("clientSelected")});
}
Template.addHours.events({
'change select[name="clientsDD"]' : function(event){
newClient = $(event.target).val();
Session.set("clientSelected", newClient);
},
'change select[name="projectsDD"]' : function(event){
newProject = $(event.target).val();
}
});
There are two ways in my mind this can be done. As Meteor doesn't require page reloads to update your content. There is nothing to stop you have the row save on completion and then just having a loop which populates the page. Your form becomes something like this:
<form id="add_time">
{{#each rows}}
{{> row}}
{{/each}}
{{> row}}
<input type="submit" id="submit_hours" value="Save and Add Another"/>
<input type="button" id="submit_and_exit" value="Save and Exit"/>
</form>
<template name="row">
<ul>
{{> clientsDD _id}}
{{> projectsDD _id}}
{{> hoursAndTasks _id}}
</ul>
</template>
This would loop through a rows helper which contains your hours data displaying it for editing along with providing a new empty row. This would automatically update on save with no need for any DOM manipulation.
The other option is to duplicate the fields. I'm not aware of a method that allows you to duplicate a template but there's no reason why jQuery clone type function wouldn't work however you'd need to make sure that on saving they are saved separately. clientsDD[] as the input names should be okay as long as you give each group of fields a unique id.
I would personally use the first method thou as IMHO this is the way Meteor is designed to work so you don't have the need to manipulate the DOM as it will seamlessly update with the data store.