I am trying to add pagination support to my meteor app but my template shows a blank page as soon as I add the {{{pagination}}} tag in my template. There are no errors in the log.
My client js (routing info) looks like this
Meteor.Router.add({
'/': function () {
var user;
if (Meteor.loggingIn()) {
console.log('home: loading');
return 'loading';
}
user = Meteor.user();
if (!user) {
console.log('homer: signin');
return 'user_signin';
}
// start on 'start' page
console.log('home: start');
return 'page';
},
'/landing': 'landing',
'*': 'not_found',
'/landing/:page': function (page) {
Session.set('page', page) ;
return 'landing' ;
}
});
My Landing.js looks like this
Template.userList.pagination = function () {
return Pagination.links('/landing', Meteor.users.find({}).count(), {currentPage: Session.get('page'), perPage: 8}) ;
}
My landing template is as follows:
</thead>
<tbody>
{{#each users}}
{{> user}}
{{/each}}
{{{pagination}}}
</tbody>
</table>
I see a couple things with the code posted.
I don't know much about the Pagination addin but it looks like you have it inside the table tag and according to this (https://github.com/egtann/meteor-pagination) it renders a div. I believe that would be invalid.
In your routes you have the wildcard '*' before the 'landing/:page'. I believe it would match that one first. Should have the '*' be the last route you add.
Related
I am trying to show my backend data from mongoDB into front-end and calculate the balance of a particular member
Here is the code:
export default function BuySellInfo() {
const[xnaLogData,setXnaLogData]=useState([]);
const [balance,setBalance]=useState(0);
const calBal =()=>{
var sum = xnaLogData.reduce(function(prev, current) {
return prev + +current.balance
}, 0);
setBalance(sum);
}
useEffect(() => {
async function fetchXna () {
const response = await fetch('/xnaloginforoute');
const json = await response.json();
setXnaLogData(json.xnacomp);
console.log(json.xnacomp)
console.log(xnaLogData);
}
fetchXna();
calBal();
},[]);
return (
<div>
<table className="table" style={{width:"30%",marginLeft:"3%"}}>
<tbody>
<h2 style={{textAlign:'center'}}> Buy & Sell </h2>
<tr>
<td>Member No</td>
<td>{xnaLogData[0].memberno}</td>
</tr>
<tr>
<td>XNA Balance</td>
<td>{balance}</td>
</tr>
</tbody>
The above component will fetch the data from the back-end route. Although the route is working fine with postman whenever i send the request but its showing error in the front-end . And the error is sometimes removed (which means data fetched perfectly) but on the first attempt the data is not fetched, after commenting or uncommenting the line of code : {/* <td>{xnaLogData[0].memberno}</td> */}
from above component the fetch api work. I am unable to sort out this issue.
The back-end route is :
router.get('/xnaloginforoute', async (req, res) => {
const xnacomp=await xnaLog.find({})
res.json({xnacomp});
});
What i had figured about this issue that response is not fetched in first attempt in front-end but through Postman it is working correctly. But i am unable to solve this issue.
And how to get the data or fetch is that:
First click on BuySell button to open this component
It will show error of TypeError: Cannot read properties of undefined (reading 'memberno') as i had not comment out the line { <td>{xnaLogData[0].memberno}</td> }
But then i comment the line {/* <td>{xnaLogData[0].memberno}</td> */} and the table will appear with no values as the line of code is comment out
Then i uncomment the line { <td>{xnaLogData[0].memberno}</td> } the data will be fetched perfectly and stored in usestate
I couldnt understand the things in this code.
Put this line under your useEffect and above your return:
if (!xnaLogData.length) {
return null;
}
You're fetching data for your table that's not going to be available at initial render of the component so xnaLogData[0] is undefined
I have a collection with various data that I would like to use when rendering my ejs page. I only seem to be able to render contents from ONE query and not other queries.
Kindly help me figure out how to render the contents from other queries.
Find below some of the contents of my collection:
Find below my rendered ejs page
Pay special attention to the Unidentified in the Transactions from: Unidentified county sentence.
Now... lets take a look at the code that generates this page:
function county (req, res) {
transModel.findOne({ transCounty : /Nairobi/i,
})
.limit(5)
.select({ transCounty:1})
.exec( (err, result)=> {
if (err) throw err;
console.log('>> ' +result);
console.log('We in county function!');
return result;
});
};
app.get('/list', async (req,res)=> {
console.log('## ' +county());
transModel.find({transIndustry: 'Pharmacy'}, (err, docs)=> {
if (!err)
{
res.render('list', {data : docs, countyName: county});
}
else
{
// res.status(status).send(body);
}
})
});
In the console, the code above logs:
## undefined
>> { _id: 609f7ed8fe1fd8b3193b0b77, transCounty: 'Nairobi' }
We in county function!
And now find below the ejs file contents:
<body>
<h1>
Transactions
</h1>
<p> Transactions from: <b> <%= countyName.transCounty %> </b> County: </p>
<table>
<tr>
<th> _id </th>
<th> Transaction Amount </th>
<th> Transaction Industry </th>
</tr>
<% data.forEach(function(entry) {%>
<tr>
<td> <%=entry._id%> </td>
<td> <%=entry.transAmount%> </td>
<td> <%=entry.transIndustry%> </td>
</tr>
<%});%>
</table>
Kindly help me understand where I am going wrong and how I can get the <%= countyName.transCounty %> to display Nairobi in my rendered ejs file
The main difference between docs and county is that docs is the results from a database-query (ok!), while county is a function which you only reference to and never run (problem 1), but if you were to run it still returns nothing (problem 2), but it does run a query, so you have that going for you!
so, not the complete solution, but just to point you in the right direction:
You need to call county at some point using county() with parenthesises.
Since the nature of database queries is that they are asynchronous you need to either use a callback pattern or a promise-based solution.
A callback solution could look like:
// Here we are calling the function, and the entire function-argument is the callback.
county((countyResult /* the callback will be called with result in the future */) => {
// wrap your existing code,
// because the result will only be available inside the callback
transModel.find({transIndustry: 'Pharmacy'}, (err, docs) => {
...
res.render('list', {data : docs, countyName: countyResult});
});
});
And the called function could look something like this:
function county (callback /* accept a callback */) {
transModel.findOne({ transCounty : /Nairobi/i })
.limit(5)
.select({ transCounty:1})
.exec((err, result) => {
if (err) throw err;
callback(result); // Use the callback when you have the result.
});
}
Because the need to wrap callbacks the result never becomes very pretty.
Instead you could use promises. for example:
let countyResult = await county();
let docs = await transModel.find({transIndustry: 'Pharmacy'}).exec();
res.render('list', {data : docs, countyName: countyResult});
And the called function could look something like this:
function county (req, res) {
return transModel
.findOne({ transCounty : /Nairobi/i })
.limit(5)
.select({ transCounty: 1})
.exec(); // If you use exec without a callback it'll return a promise.
};
This is much cleaner but error handling needs to be done using try/catch.
For example:
let countyResult;
try {
countyResult = await county();
catch(err) {
throw err;
// Of course, if all you do is throw, then you don't even need the `try/catch`.
// Try/catch is to catch thrown errors and handle them.
}
You still might want to check that the result contains anything. A query with no data found is not an error.
Disclaimer: The code is for describing the flow. I've tried to get it right, but nothing here is tested, so there is bound to be errors.
I have a template like this,
<template name = "foo">
<p id="loading" >LOADING...</p>
<p> {{theResult}} </p>
</template>
This is how I create foos,
// foos = [a, b, c, d]. With each button click I add a new item to the array
{{#each foos}}
{{> foo .}}
{{/each}}
And how a foo works,
Template.foo.created = function(){
var name = Template.currentData();
api_call(name, function(err, result){
Session.set(name, result);
});
}
Template.foo.helpers({
'theResult': function(){
var name = Template.currentData();
if(Session.get(name)) {
$("#loading").hide();
return Session.get(name);
} else {
return "";
}
}
})
So my expectation is to when the data came from the api_call, to hide "LOADING..." para, and to show the result in theResult.
The result is showing correctly. My problem is "LOADING..." is only get hidden on the top most foo. Not the other ones.
How can I fix this?
EDIT:
As suggested instead of,
$("#loading").hide();
I used,
Template.instance().$("#loading").hide();
This didn't work too :)
This is how I'd do it
Template... if theResult is undefined, the else path will be rendered.
<template name="foo">
{{#with theResult}}<p> {{this}} </p>
{{else}}<p id="loading" >LOADING...</p>
{{/with}}
</template>
Javascript... theResult is a simple Session.get call
Template.foo.helpers({
theResult: function(){
var name = Template.currentData();
return name && Session.get(name);
}
});
Thanks to Meteor templating engine, you can access a template scoped jQuery object that will only return elements within the corresponding template.
Template.foo.helpers({
'someText': function(){
var template = Template.instance();
template.$('p').changeSomeattr();
return Session.get('myPara');
}
});
I've a problem with the Reconciliation algorithm using a set of key (without duplicates). The snippet of code is similar to the examples:
`
var ResourceTable = React.createClass({
getInitialState: function() {
return {data: [{"rid": "Ciao ", "id": 10}, {"rid": "Mondo!", "id": 2}]};
},
componentDidMount: function() {
self = this;
self.setState({data: [{"rid":"first", "id": 3},{"rid":"second", "id": 1},{"rid":"third", "id": 2}]});
},
render: function() {
var commentNodes = this.state.data.map(function (resource, index) {
return (
<Resource key={resource.id} rid={resource.rid}/>
);
});
return(
<table>
{commentNodes}
</table>
);
}
});
`
The first time that the object is rendered everything works fine (for every value of the resource.id). The second time I've an unattended behavior: sometimes every element is correctly rendered and sometimes not, I made a lot of attempts, but I cannot find an explanation.
The case that cause the error is:
First rendering keys: [10,2]
Second rendering keys: [3,1,2]
The result is that only two element are rendered during the second rendering.
React is very sensitive if you are rendering HTML which is mutating in browser. This is the case with <table>, which can be created like this:
<table>
<tr><td>Cell</td></tr>
</table>
But in fact browsers are changing it to:
<table>
<tbody>
<tr><td>Cell</td></tr>
</tbody>
</table>
After this operation DOM and React Virtual DOM differs and triggers errors like yours. To fix it just change:
return (
<table>
{commentNodes}
</table>
);
into:
return (
<table>
<tbody>{commentNodes}</tbody>
</table>
);
My Model :
App.Contacts = DS.Model.extend({
name : DS.attr('string'),
number : DS.attr('number')
});
This is how i save a record :
App.AddController = Ember.Controller.extend({
actions : {
addContact : function(){
var post = this.store.createRecord('Contacts',{
name : this.get('name') ,
number : this.get('number')
});
post.save();
}
}
});
Acc to Ember's offical guide, this would send a POST request to /Contacts , so to handle it, i used this in nodejs/expressjs
app.post('/contacts',function(req,res){
posts.push( req.body);
console.log(posts);
res.send({status: 'OK'});
});
Now i wish to retrieve it, into another template called all so i used :
App.AllRoute = Ember.Route.extend({
model : function(){
return this.store.find('Contacts');
},
setupController : function(controller,model){
controller.set('contactList',model);
}
});
Acc to Emberjs guides, model hook supports promises out-of-the-box . so i assumed this should work.
My template :
<script type="text/x-handlebars" id="all" >
Hello
<table>
{{#each contact in contactList}}
<tr>
<td>{{contact.name}} </td>
<td>{{contact.number}} </td>
</tr>
{{else}}
<tr><td>No contacts yet </td> </tr>
{{/each}}
</table>
</script>
Question
But the model returns nothing, i understand that this.store.find('Contacts') doesn't return a javascript array, but essentially and object , implimenting Ember.Enumerable
But on the server side, the posts is an javascript array, therefore there might be an type mismatch between then. how to resolve this?
EDIT:
To avoid any confusions in client side Ember code , This works properly, so there is some problem with the round trip to server.
App.AllRoute = Ember.Route.extend({
model : function(){
return this.store.all('Contacts');
},
setupController : function(controller,model){
controller.set('contactList',model);
}
});
If you could provide a jsfiddle, it be nice. I'm not sure whether contactList is defined or not and whether the alias for that controller is actually defined. So based on what I see, I think the problem is you're iterating over a controller that does not have the model properly defined.
I'd suggest trying to do:
{{#each}}
<tr>
<td>{{contact.name}} </td>
<td>{{contact.number}} </td>
</tr>
{{else}}
<tr><td>No contacts yet </td> </tr>
{{/each}}
If you really want to use the contactList controller, then you need to make sure that the App.AllController "needs" the contactListController.
App.ContactListController = Ember.ArrayController.extend({}) // needs to be an array controller
App.AddController = Ember.ArrayController.extend({
needs: ["contactList"], // controller's used within this controller
contactList: Ember.computed.alias("controllers.contactList"), // needed to iterate over the model how you're doing it.
Both of these solutions should work assuming your data is actually loaded in Ember Data. You might want to check the "data" tab on the ember-data console. If you don't have that browser extension installed, do it. It's incredibly useful.
If all else fails, try logging to verify expected values using {{log contactList}}
Good luck