Meteor Reactive Var Not Being Set - meteor

I'm getting Uncaught TypeError: Cannot read property 'chapter' of null when trying to get a Reactive Var value. I'm doing exactly the same thing with Session and it works. So I'm confused as to what I'm going wrong. Perhaps the value is being set at the wrong time?
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var'
import { Stories } from '/imports/collections/stories.js';
/* Story */
Template.story.onCreated(function(){
// Set the current chapter
this.chapter = new ReactiveVar(0);
this.page = new ReactiveVar(0);
});
Template.story.onRendered(function(){
/* Show the first fragment */
page.addEventListener( 'changed', function( event ) {
console.log( Template.instance().chapter.get() );
....
The event is being fired, but the instance of chapter isn't being set in onCreated.
What am I doing wrong here?

try this:
Template.story.onRendered(function(){
let instance = Template.instance();
/* Show the first fragment */
page.addEventListener( 'changed', function( event ) {
console.log( instance.chapter.get() );

Related

Meteor.js Tracker.autorun / Tracker.depend on exported variable from server-side with set interval

I'm trying to get my head around Meteor's Tracker.autorun and Tracker.dependancy features.
I'm trying to do something that seems simple in my mind but I'm struggling to execute.
I have a server-side function, that I register as a method:
let count = 0
setInterval(()=>{
count ++
return count
}, 1000)
export default count
Register as a method:
import count from './setIntervarl'
Meteor.methods({
getData:function() {
return count
}
});
And then call up on the client side:
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker'
import './main.html';
// Setup reactive variable
rv1 = new ReactiveVar(9)
Meteor.call('getData', function(error, results) {
if(error){
console.log("error:"+error);
} else {
rv1.set(results)
}
});
// Display the output from reactiveVar
Template.someData.helpers({
someData: function() {
return rv1.get();
}
})
Can someone please show me how to use Tracker.autorun or Tracker.dependancy so that my UI updates with interval that is set in my server-side function
I'm having really trouble getting this working.
Many thanks
There will be no reactivity out of the box here. Meteor methods are not reactive but just a wrapped ddp call to a server (rpc-) endpoint that returns something.
In order to gain reactive data from the server, you need to subscribe to a publication. If you want only this counter being published, you may create a collection with a single document and publish it.
imports/CountCollection.js (both)
export const CountCollection = new Mongo.Collection('myCounter')
server/counter.js (server)
import { CountCollection } from '../imports/CountCollection'
let counterDocId
Meteor.startup(() => {
// optional: clear the collection on a new startup
// this is up to your use case
// CountCollection.remove({})
// create a new counter document
counterDocId = CountCollection.insert({ count: 0 })
// use the Meteor.setInterval method in order to
// keep the Meteor environment bound to the execution context
// then update the counter doc each second
Meteor.setInterval(function () {
CountCollection.update(counterDocId, { $inc: { count: 1 } })
}, 1000)
})
// Now we need a publication for the counter doc.
// You can use the `limit` projection to restrict this to a single document:
Meteor.publish('counterDoc', function () {
if (!counterDocId) this.ready()
return CountCollection.find({ _id: counterDocId }, { limit: 1 })
})
Now you can subscribe to this publication and get reactive updates to the document:
client/someData.js (client)
import { CountCollection } from '../imports/CountCollection'
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker'
import './main.html';
// Setup reactive variable
const reactiveCounter = new ReactiveVar(0)
const counterSubscription = Meteor.subscribe('counterDoc')
Template.someData.onCreated(() => {
const instance = this
instance.autorun(() => {
// counterSubscription.ready() will re-called
// when the publication released a new cursor
// which causes the autorun to re-run = reactivity
if (counterSubscription.ready()) {
// there is only 1 doc published, so no query require
const counterDoc = CountCollection.findOne()
reactiveCounter.set(counterDoc && counterDoc.count)
}
})
})
// Display the output from reactiveVar
Template.someData.helpers({
someData: function() {
return reactiveCounter.get()
}
})
Sidenote:
don't forget to get the paths and imports correct
Readings:
https://docs.mongodb.com/manual/reference/operator/update/inc/
https://docs.meteor.com/api/timers.html#Meteor-setInterval

Meteor subscribe is not loading data from the server

I am having difficulties with meteor 1.6. First, I have created a database instance and tried to subscribe in the client. through form, I am able to input the data into my database. But could not retrieve it through the subscribe. can anybody tell me what wrong have I done in my code?
import { Template } from "meteor/templating";
import { Notes } from "../lib/collection";
import { Meteor } from "meteor/meteor";
// import { ReactiveDict } from 'meteor/reactive-dict';
import "./main.html";
/*
Template.body.onCreated(function bodyOnCreated() {
this.state = new ReactiveDict();
Meteor.subscribe("db1");
}); */
Template.Display.helpers({
notes() {
Meteor.subscribe("db1");
return Meteor.call('data');
}
});
Template.body.events({
"click .delete": function() {
Notes.remove(this._id);
},
"submit .formSubmit": function(event) {
event.preventDefault();
let target = event.target;
let name = target.name.value;
Meteor.call("inputs", name);
target.name.value = "";
return false;
},
"click .userDetail": function() {
if (confirm("Delete the user Detail ?")) {
Notes.remove(this._id);
}
}
});
here is the code for publication :
import { Mongo } from 'meteor/mongo';
export const Notes = new Mongo.Collection('notes');
Meteor.methods({
inputs:(name)=> {
if (!Meteor.user()) {
throw Meteor.Error("Logged in");
}
Notes.insert({
name: name,
createdAt: new Date()
});
},
data:()=>{
return Notes.find({});
}
});
Meteor.subscribe("notes"); should be in Template.body.onCreated lifycycle method. you need to write a
publish code seperately and not inside the Meteor.method. see below format,
Meteor.publish('notes', function tasksPublication() {
return Notes.find({});
});
Inside the helper just call the subscribed Collection a below,
Template.Display.helpers({
notes() {
return Notes.find({});
}
});
**NOTE: ** Never use Meteor.call inside the helper method. helpers are reactive and real time.

Meteor application - object appears in the terminal, but DATA appears undefined on the client side

import { Meteor } from 'meteor/meteor';
Meteor.methods({
'harmonized'(text){
HTTP.call( 'GET', 'https://hts.usitc.gov/api/search', { params: {
"query": text
}}, function( error, response ) {
if ( error ) {
console.log( error );
} else {
return response.data.results;
}
});
}
});
The above code gives me the array of objects in my terminal
import './shipping_steps.html';
import { HTTP } from 'meteor/http'
Template.shipping_steps.events({
// data: [],
'submit .hs': function(){
event.preventDefault();
//get Input value
const target = event.target;
const text = target.search.value;
//clear the form
target.search.value = "";
const data = Meteor.call('harmonized', text);
console.log(data);
return false;
}
})
When I try to store the array of objects on the client, I am not
able to do so and client logs out as undefined. However, for this
code, it is grabbing information from an input field on client
From your code data hasn't returned a value yet. You need to store the result on a reactive variable or a session variable.

render() method is not correctly called after props update

I'm doing a very simple react+redux application where I've a reducer called goals and a container called GoalsContainer.
From App Container I call the action goal for load the initial goals from a local db(indexedDB)
dispatch(loadGoals(currentDate));
This call the loadGoals from the goals actions:
export function loadGoals(currentDate = new Date()){
return dispatch => {
var goals = getGoalsFromDB(normalizeDate(currentDate)); // with this I get an array from the db
dispatch(setLoadGoals(goals));
}
}
function setLoadGoals(goals) {
return {
type: types.LOAD_GOALS,
goals
};
}
And then in my reducer I've this:
export default function goals(state = [], action) {
switch(action.type) {
case types.LOAD_GOALS:
return action.goals; // here I set the state of the goal reducer with the array passed via action
default:
console.log('Im here');
return state;
}
}
and this is my GoalsContainer(read the comments in code):
class GoalsContainer extends React.Component {
render() {
if (this.props.goals != undefined) {
console.log('ok called the render'); // in chrome console shows it
console.log(this.props.goals); // in chrome console shows correctly the goals loaded
console.log(this.props.goals.length); // it say 2
if (this.props.goals.length > 0) { // here fails...
console.log('good');
console.log(this.props.goals);
var goalsView = <div>There are goals</div>
}
else {
console.log('why go here?'); // go here
console.log(this.props.goals);
var goalsView = <div>No goals</div>
}
} else {
var goalsView = <div>Undefined</div>
}
return (
<div id="goals-main">
{goalsView}
</div>
);
}
}
GoalsContainer.propTypes = propTypes;
function mapStateToProps(state) {
const { goals, environment } = state;
const { currentDate } = environment;
return {
goals,
currentDate
}
}
export default connect(mapStateToProps)(GoalsContainer);
The problem is that when it does the if check, it fails(like if there are 0 goals), but in chrome console show correctly the goals array...
Then if I force with some workaround the render(), all works correctly.
What I've done wrong ?
You didn't mention if you use https://github.com/gaearon/redux-thunk or not. To use reducer returning function you should definitely install it.
It's hard to follow all of the parts of your code from random gists. What happens if you change your GoalsContainer to be;
class GoalsContainer extends React.Component {
render() {
console.log(this.props.goals);
return (
<div id="goals-main">
{(this.props.goals.length >= 1)?<div>There are goals</div>:<div>Nope!</div>}
</div>
);
}
}
What gets logged to the console?

React rendering recursion stops without error

I've encountered a problem with rendering some elements in React.
(I use ImmutableJS)
renderComponents: function(components) {
if(components.isEmpty()) return [];
var table = [];
components.map(function(component) {
table.push(<ComponentTableElement key={ component.get('id') } data={ component } />);
if(component.has('children')) {
var children = component.get('children');
table.concat(this.renderComponents(children));
}
});
return table;
},
As I looked for error, I found that this.renderComponents(children) doesn't return anything at all and the code somehow stops.
I mean before that line everything works ok, but then after this line, when i try to console.log something, it doesn't show up. And it doesn't even reach return table.
So what is wrong with that code?
In the context of the function you pass to map, this refers to the window object, not to the current component instance, so this.renderComponents is undefined when you try to call it.
components.map(function(component) {
this === window;
});
You can pass a value to use as this in the body of your function as the second parameter of Array::map.
components.map(function(component) {
table.push(<ComponentTableElement key={ component.get('id') } data={ component } />);
if(component.has('children')) {
var children = component.get('children');
// here, `this` refers to the component instance
table.concat(this.renderComponents(children));
}
}, this);
If you're using ES6, you can also use fat-arrow functions, which are automatically bound to this.
components.map((component) => {
table.push(<ComponentTableElement key={ component.get('id') } data={ component } />);
if(component.has('children')) {
var children = component.get('children');
// here, `this` refers to the component instance
table.concat(this.renderComponents(children));
}
});

Resources