Jade Cannot read property 'length' of undefined in each loop - node.js

I have this code in my controller retrieving an object from mongo and sending it to the client:
index: function(req, res){
List.find({user:req.session.user.id}).exec(function foundLists(error, foundLists) {
if(error) {
return res.json({error:error});
} else {
return res.view({ title:'Lists',lists:foundLists });
}
});
}
In my view I do the following:
extends ../layout
block content
.container
p #{lists}
Which renders:[object Object],[object Object]
If I do p= JSON.stringify(lists)
It renders:
[{"user":"546109c0d640523d1b838a32","name":"third","createdAt":"2014-11-11T19:39:36.966Z","updatedAt":"2014-11-11T19:39:36.966Z","id":"546265f83e856b642e3b3fed"},{"user":"546109c0d640523d1b838a32","name":"forth","createdAt":"2014-11-11T19:42:09.268Z","updatedAt":"2014-11-11T19:42:09.268Z","id":"546266913e856b642e3b3fef"}]
I'm trying to achieve:
#lists
each list in lists
p #{list}
But I get this error:
Cannot read property 'length' of undefined
I'm using Sails and Jade 1.7.0

You have an array of objects, so if you do each list in lists then list is an object. I assume Jade wants a string. If you put p #{list.name} or something similar that should work.
If you want to show everything you can try nesting your loops like
each list in lists
each item in list
p #{item}

This error can occurred when at least one of the items in the lists does not have a list property. You can protect this using an if statement:
each val in lists
if val.list
each item in val
p #{item}

Related

*ngFor loop over mLab objects produce Error trying to diff'[object Object] even after declaring array

I have an array declared as carousels: any = [] in my TS file but I keep getting an error stating 'only arrays and iterables allowed' whenever I loop over it using *ngFor. The data inside this array is acquired from mLab.
The goal of my code is to update an object from mLab using its id which seems to work fine. But whenever I press the update, given the fact that the update even works, why do I still get the error?
I have tried to change carousels: any = [] to just carousels = [] but it doesn't seem to change anything.
This is my code.
api.js (backend) - this is the code that communicates with the database.
router.route('carousel/update/:_id).put(function(req, res) {
db.collection('home').updateOne({"_id": ObjectId(req.params._id)}, {$set: req.body}, (err, results) => {
if (err) throw err;
res.send(results)
console.log(req.params._id)
});
});
home.service.ts
return this.http.put<any[]>('./api/carousel/update/' + id, {'header': newheader, 'subheader': newsubheader})
}
component.ts
declaration:
carousels: any = [];
update function:
updateSlide(id: number){
this.HomeService.updateSlide(id, this.header, this.subheader).subscribe(slides => {this.carousels = slides})
}
Update works but I still get the Error: error trying to diff '[object object]'. only arrays and iterables are allowed
The .updateOne({}) doesn't return a list of objects, but an object with the information about the row updated.
You are returning that Object from the API and then setting it in the updateSlider() in your component, where you should be setting an array instead.
Try to log the results in the api or slides in the Subscription, and you should be able to see the issue.
After several readings and posts, I have found out that my mistake was tha I manually subscribed to the Observable inside my component file.
Manually updating looks like this:
.subscribe(slides => {this.carousels = slides})
It turns out that this has already been done automatically therefore I would not need to do it again manually. Refer to this post: Pipe Async - Error trying to diff '[object Object]'. Only arrays and iterables are allowed
This fixed the issue for me.

Display properties of nested GeoJson in Mapbox

I am unable to query nested properties feature, which is imported from a geojson source and displayed on a mapbox map.
I am able to get the feature with an on click listener, but as soon as the property is nested, the object is represented as a string
{
...
properties: {
address: "{"place":"Bern","street":"Fischerweg","street_nr":"11","zip":"3012"}"
price: 4500
}
}
Therefore I am only able to display the not-nested properties in a popup, when it is clicked.
my code:
const features = this.queryRenderedFeatures(e.point, {
layers: ['unclustered-point']
});
console.log(feature.properties.price) --> 4500
console.log(feature.properties.address) --> string instead of object {"place":"Bern","street":"Fischerweg","street_nr":"11","zip":"3012"}
console.log(feature.properties.address.street) --> undefined (--> NOT WORKING because of nested property)
const popup = new mapboxgl.Popup({offset: [0, -15]})
.setLngLat(feature.geometry.coordinates)
.setHTML('<h3>Price: ' + feature.properties.price + '</h3>
<p>Street: ' + feature.properties.address.street + '</p>')--> NOT WORKING because of nested property
.setLngLat(feature.geometry.coordinates)
.addTo(map);
I read that you can access nested properties with expressions, but how can expressions be applied in the html of the popup?
Is there a way how I can access the nested properties or do I have to redesign the geojson's structure?
any help is highly appreciated! Thank you so much,
Regards Simon
Since the property values are converted into JSON strings, you need a reverse conversion:
Object.keys(feature.properties).forEach(function(key) {
feature.properties[key] = JSON.parse(feature.properties[key]);
});
[ https://jsfiddle.net/s1d7hL82/ ]

Meteor exception in Meteor.flush when updating a collection breaks reactivity across clients

When I'm calling Collection.update from the front end (the method call is allowed), the update does work ok, but the exception below is being thrown (in Chrome's JS console, not in the server). Although the update took place, other clients connected to the same collection do not see the updates until they refresh the browser - I suspect because of the exception.
Any idea what might cause this?
Exception from Meteor.flush: Error: Can't create second landmark in same branch
at Object.Spark.createLandmark (http://checkadoo.com/packages/spark/spark.js?8b4e0abcbf865e6ad778592160ec3b3401d7abd2:1085:13)
at http://checkadoo.com/packages/templating/deftemplate.js?7f4bb363e9e340dbaaea8d74ac670af40ac82d0a:115:26
at Object.Spark.labelBranch (http://checkadoo.com/packages/spark/spark.js?8b4e0abcbf865e6ad778592160ec3b3401d7abd2:1030:14)
at Object.partial [as list_item] (http://checkadoo.com/packages/templating/deftemplate.js?7f4bb363e9e340dbaaea8d74ac670af40ac82d0a:114:24)
at http://checkadoo.com/packages/handlebars/evaluate.js?ab265dbab665c32cfd7ec343166437f2e03f1a54:349:48
at Object.Spark.labelBranch (http://checkadoo.com/packages/spark/spark.js?8b4e0abcbf865e6ad778592160ec3b3401d7abd2:1030:14)
at branch (http://checkadoo.com/packages/handlebars/evaluate.js?ab265dbab665c32cfd7ec343166437f2e03f1a54:308:20)
at http://checkadoo.com/packages/handlebars/evaluate.js?ab265dbab665c32cfd7ec343166437f2e03f1a54:348:20
at Array.forEach (native)
at Function._.each._.forEach (http://checkadoo.com/packages/underscore/underscore.js?772b2587aa2fa345fb760eff9ebe5acd97937243:76:11)
EDIT 2
The error will also occur if the update call is run in the console. It happens on the first run of the update but by then reactivity is broken on any other browser attached to it.
EDIT
Here is my template for the clickable item that triggers the update:
<template name="list_item">
<li class="checklistitemli">
<div class="{{checkbox_class}}" id="clitem_{{index}}">
<input type="checkbox" name="item_checked" value="1" id="clcheck_{{index}}" class="checklist_item_check" {{checkbox_ticked}}> {{title}}
</div>
</li>
</template>
and here's the event handler for clicks on 'list_item':
Template.list_item.events = {
'click .checklistitem' : function(ev) {
this.checked = !this.checked;
var updateItem = {};
updateItem['items.'+this.index+'.checked'] = this.checked;
console.log("The error happens here");
Lists.update({_id: this._id}, {$set:updateItem}, {multi:false} , function(err) {
console.log("In callback, after the error");
});
}
}
The whole thing is available at http://checkadoo.com (Its a port of a Tornado based Python app of mine)
I've found this is usually an issue with duplicate ids. #Harel's question doesn't include the code that actually renders the collection so we can't tell the root cause of his problem but the repro that #Drew supplied in the comments is throwing this error because it is rendering an array of objects that have duplicate '_id' values.
I have put together a working version of #Drew's repro:
https://github.com/alanning/meteor-buggy-fix
The key fix is to ensure the inserted drink items do not have duplicate '_id' fields:
Template.drink_from_menu.events({
'click .buy_drink': function () {
var drink = {name: this.name, price: this.price};
console.log("this = ", this);
// using 'this' doesn't work because it already has a '_id' field and
// you would be trying to render multiple drinks with the same id
// which causes Spark to throw the "Can't create second landmark
// in same branch" error
//Tabs.update({_id:Session.get('tabId')}, {$push: {ordered_drinks: this}});
// either ensure that the objects you want Spark to render have a
// unique id or leave off the _id completely and let Spark do it for you
Tabs.update({_id:Session.get('tabId')}, {$push: {ordered_drinks: drink}});
}
});

How do I render a nested data structure with Node.js/Jade

In my .js file I have the following data structure
var menu = { "Sport":"Racing",
"Region":{
"AUS":{ "name":"APrk", "key":"1234" },
"GB":{ "name":"Cran", "key":"5678" }
}
};
res.render('layout.jade', {locals: {menu: menu}});
In my layout.jade I have the following
for item in menu
p= item
This produces the following output
Racing
[object Object]
Which is on the right track. What I would like to know is how can I access the nested structures?
I believe you're looking for this
// layout.jade
each value, key in locals.menu
// may nest more iteration
each v, k in value
Iteration of object key/value does not grantee order. You may want to use array.
Details: https://github.com/visionmedia/jade#a9

How do I call function from jade client side java scripts

I have two drop down lists in my form. Once user selected value from first list I want to filter second list as per selection and display. For that I am using onchange="showSubCat(); of first select option to get selected value. showSubCat() function is defined in client side js file. How do I get value returned by showSubCat() function in jade template so that I can filter array which is populating second list.
var subcode = showSubCat();
gives error.
Any suggestions?
Thank you.
New to Jade myself but as far as I can tell you have two options:
1) create the function in jade itself:
-function sayHi(name){
- return "hello "+name
-}
p= sayHi('bill')
Which I think muddies up your code a bit.
2) A better option would be to pass in the function from the model
app.get('/', function(req, res){
res.render('home', {
title: 'Home'
, fs: { sayHi:function(name){
return "hello "+name
}}
});
});
Then in your jade file you just:
p= fs.sayHi('bill')

Resources