I'm trying to make a Meteor helper non-reactive with this code:
let titleNonReactive;
Template.articleSubmission.onCreated(function () {
this.autorun(function() {
titleNonReactive = Template.currentData().title;
});
});
Template.articleSubmission.helpers({
titleNonreactive: function() {
return titleNonReactive;
}
});
However the resulting output is still reactive. If I save a new value in the background, it's automatically updated on the frontend where I'm displaying the result of this helper with {{ titleNonreactive }}.
How can I fix this?
This is likely caused by your Blaze data context (will need to see your Template code to confirm), but here's a possible solution that doesn't involve using Tracker.nonreactive. Since you want the value of titleNonreactive to not be reactive, you can just use a standard local / non-reactive variable to store a copy of the original reactive title. For example:
import { Template } from 'meteor/templating';
import { articles } from '/imports/api/articles/collection';
import './main.html';
let originalTitle;
Template.body.onCreated(function onCreated() {
this.autorun(() => {
const article = articles.findOne();
if (article && !originalTitle) {
originalTitle = article.title;
}
});
});
Template.body.helpers({
article() {
return articles.findOne();
},
titleNonreactive() {
return originalTitle;
}
});
Then in your Template:
<ul>
{{#with article}}
<li>Reactive Title: {{title}}</li>
<li>Non-Reactive Title: {{titleNonreactive}}</li>
{{/with}}
</ul>
Related
I have the following structure:
{
id: 23423-dsfsdf-32423,
name: Proj1,
services: [
{
id:sdfs-24423-sdf,
name:P1_Service1,
products:[{},{},{}]
},
{
id:sdfs-24jhh-sdf,
name:P1_Service2,
products:[{},{},{}]
},
{
id:sdfs-2jnbn3-sdf,
name:P1_Service3,
products:[{},{},{}]
}
]
},
{
id: 23423-cxcvx-32423,
name: Proj2,
services: [
{
id:sdfs-xvxcv-sdf,
name:P2_Service1,
characteristics:[{},{},{}]
},
{
id:sdfs-xvwqw-sdf,
name:P2_Service2,
characteristics:[{},{},{}]
},
{
id:sdfs-erdfd-sdf,
name:P2_Service3,
characteristics:[{},{},{}]
}
]
}
I have no problem creating a form this schema an insert form with quickForm.
But I cant figure out (and tried to read every tutorial and instruction and nothing worked) how to create an update form with all fields filled and (need to expand and fill the services and the characteristics arrays also:
of course, as i said, in update i need the services and characteristics to expend to the right size with all the fields.
But if i could understand how to fill the form fields i could understand myself how to expend the arrays...
i've tried:
{{> quickForm collection="Projects" id="updateProjectForm" collection="Projects" type="method" class="update-project-form" doc=project }}
with:
import SimpleSchema from 'simpl-schema';
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
// Attaching the subscription to the template so we can reuse it
Template.ProjectSingle.onCreated(function(){
var self = this;
self.autorun(function(){
var id = FlowRouter.getParam('id');
self.subscribe('projectSingle', id);
});
});
Template.ProjectSingle.helpers({
project: ()=> {
var id = FlowRouter.getParam('id');
console.log(Projects.findOne({_id: id}));
return Projects.findOne({_id: id});
}
});
I can't even see the console.log() printing.
This solution at list didn't crash the meteor server... everything else i've tried crashed the server on many errors
Maybe i need to mention that i'm using partials so maybe there is a problem with the JS files but i don't think so as the onCreated method is being read.
10x.
EDIT:
I've removed the partial for the update template and it is now in the root Template with its own JS with the method:
projectDoc: ()=> {
var id = FlowRouter.getParam('id');
console.log("Update: " + Projects.findOne({_id: id}));
return Projects.findOne({_id: id});
}
Now i can see this method is being called but for some reason it is being called twice. First with the correct data and then getting undefined so i've still not getting the fields showing anything but if i could find why it is being called twice i will solve the first level form (no services and so on)
Solved it (Not sure this is the best way as i'm still having two calls to the method but this is working for now:
projectDoc: ()=> {
var id = FlowRouter.getParam('id');
if(Projects.findOne({_id: id}) != null){
console.log(Projects.findOne({_id: id}));
thisProject = Projects.findOne({_id: id});
return Projects.findOne({_id: id});
} else {
return thisProject;
}
}
When running helper brings values are stored in the variable verCandidatos.postulados.
Once I get me the information I need to get a document that is linked (using the function ng-init="candidato = la postulado.candidato()) wich runs on the helper from file: collection.js.
Sometimes the html shows the properties: {{candidato.nombre}}, {{candidato.apellidos}} and {{candidato.sexo}} correctly, and sometimes appear empty, why?
Is very strange, like a bug or something. How is possible that behavior?
The information is being obtained, because the ng-repeat works and shows elements.
Below is the publishComposite(), collection.js, html and js client
html client
my-app/imports/ui/components/vacantes/verCandidatos/ verCandidatos.html
<div ng-repeat="postulado in verCandidatos.postulados">
<div ng-init="candidato = postulado.candidato();">
{{candidato.nombre}}
{{candidato.apellidos}}
{{candidato.sexo}}
</div>
</div>
js in client
my-app/imports/ui/components/vacantes/verCandidatos/ verCandidatos.js
imports ...
class VerCandidatos {
constructor($scope, $reactive, $stateParams) {
'ngInject';
$reactive(this).attach($scope);
this.vacanteId = $stateParams.vacanteId;
this.subscribe('vacantes.candidatosOseleccionados', ()=> [{vacanteId: this.vacanteId}, {estado: 1}]);
this.helpers({
postulados (){
return Postulaciones.find();
}
});
}
}
collection.js
my-app/imports/api/postulaciones/ collection.js
imports...
export const Postulaciones = new Mongo.Collection('postulaciones');
Postulaciones.deny({...});
Postulaciones.helpers({
candidato(){
return Candidatos.findOne({_id: this.candidatoId});
}
});
publish.js:
my-app/imports/api/vacantes/server/ publish.js
imports...
if (Meteor.isServer) {
Meteor.publishComposite('vacantes.candidatosOseleccionados', function (vacanteId, estado) {
const selector = {$and: [estado, vacanteId]};
return {
find: function () {
return Postulaciones.find(selector);
},
children: [
{
find: function (postulacion) {
return Candidatos.find({_id: postulacion.candidatoId}, {
fields: {
nombre: 1,
apellidos: 1,
sexo: 1,
}
});
}
}
]
};
});
}
Any ideas?
- Thanks,
The ISSUE was in html
The solution was deteted ng-init and call directly the helpers inside collection.js, the other files (js in client, collection.js, publish.js) aren't modify.
The html file is as follows:
<div ng-repeat="postulado in verCandidatos.postulados">
{{postulado.candidato().nombre}}
{{postulado.candidato().apellidos}}
{{postulado.candidato().sexo}}
</div>
Thanks for read.
And I hope you will be useful.
How can I use reactive template variables (from Template.data) in an anonymous function within the template rendered function? (I want to keep it reactive).
Template.templateName.rendered = function() {
function testFunction(){
//Log the field 'title' associated with the current template
console.log(this.data.title);
}
});
Not sure exactly what you are trying to do (like printing this.data.title whenever it changes?), but you should:
use a Reactive variable (add reactive-var package, then create a var myVar = new ReactiveVar()
If necessary, wrap your function with Tracker.autorun (or this.autorun in a template creation / rendered event).
So you could have like:
Parent template HTML:
<template name="parentTemplateName">
{{> templateName title=myReactiveVar}}
</template>
Parent template JS:
Template.parentTemplateName.helpers({
myReactiveVar: function () {
return new ReactiveVar("My Title!");
}
});
Template JS:
Template.templateName.onRendered(function() {
// Re-run whenever a ReactiveVar in the function block changes.
this.autorun(function () {
//Print the field 'title' associated with the current template
console.log(getValue(this.data.title));
});
});
function getValue(variable) {
return (variable instanceof ReactiveVar) ? variable.get() : variable;
}
What worked for me was simple using autorun() AND using Template.currentData() to grab the values from within autorun():
let title;
Template.templateName.rendered = function() {
this.autorun(function(){
title = Template.currentData().title;
});
function testFunction(){
console.log(title);
}
});
Template.templateName.onRendered(function(){
console.log(this.data.title);
});
why is this an endless loop? [ Iron Router + Fast Render + Blaze]
Router.route("/:cycle_uri", {
name: "cycle"
,template: "home"
,onBeforeAction: function () {
console.log("is there a loop here?") // this is what confirms that it's a continuous loop
var cycle = Cycles.findOne({
"uri": this.params.cycle_uri
});
if (typeof cycle === "undefined") {
this.render("notFound"); return;
} else {
ActiveCycle.set(cycle); // if I remove this, there is no continuous loop anymore... but if I remove it I don't see how to have this info in the client
this.render("home");
}
}
,waitOn: function () {
Meteor.subscribe('featuredListsPub', {
'program_id': this.params.cycle_uri
});
}
,fastRender: true
});
I was trying to update ActiveCycle variable so I can read it in the frontend but it's not actually working... I'm certainly doing something wrong, but would like to first understand why updating the reactive var is creating a loop.
I've also tried
if (ActiveCycle.get() !== cycle) {
ActiveCycle.set(cycle);
}
but it also enters a loop... which I don't understand why
for your question in the comments:
How do you subscribe to two publications:
here is my answer:
waitOn: function () {
return [
Meteor.subscribe('subscription1'), Meteor.subscribe('subscription2')
];
}
However, i strongly recommend:
Create on publication and return two cursors
Use Template level subscriptions
Good Luck!
An example of Template level subscriptions:
Template.templatename.onCreated(function () {
Template.autorun(function () {
var subscription = Meteor.subscribe('some_publication');
if (subscription.ready()) {
// do something
}
});
});
and within the template
<template name="templatename">
{{#if Template.subscriptionsReady}}
<div>Your Template here...</div>
{{else}}
<p>Loading...</p>
{{/if}}
</template>
A nice article is right here.
I'm new to Meteor and barely understand any of it but let's say I have a collection called mycollection, declared way up top so it's available in both the client and server section:
mycollection = new Meteor.Collection('MyDumbCollection');
And then I have something like this:
if (Meteor.isClient) {
Deps.autorun(function() {
Meteor.subscribe('mycollectionSubscription');
});
Template.myshittytemplate.rendered = function() {
$("#heynow").prepend(shitfuck).dosomething();
godammit = thisfuckingthing;
//paraphrasing
mycollection.insert({thing1: thisfuckingthing});
};
}
if (Meteor.isServer) {
Meteor.publish('mycollectionSubscription', function () {
return mycollection.find();
});
};
And then in my template:
<template name="myshittytemplate">
<div id ="heynow">
{{#each mycollection}}
{{{thing1}}}
{{/each}}
</div>
</template>
What I'm trying to do is have the 'thisfuckingthing' html that's created in the #heynow div saved to the collection and published to everybody. If there's a way to make Meteor simply observe changes to the dom and save them, that's even better.
I do have autopublish uninstalled, if that makes a difference. Halp.
In client Template
Template.myshittytemplate.mycollection = function() {
return mycollection.find({}).fetch();
};
Template.myshittytemplate.rendered = function() {
$(function(){
$("#heynow").prepend(shitfuck).dosomething();
godammit = thisfuckingthing;
//paraphrasing
mycollection.insert({thing1: thisfuckingthing},function(err,_id){
if(err){
console.log(err);
return;
});
console.log(_id);
});
};
}
I needed this in the Client part:
Template.myshittytemplate.mycollection = function() {
return mycollection.find();
};
Hopes this helps somebody!