I am running into a bit of an issue, I have a user object which I have an array where a user can set their own styling options when I attempt to load the page where this styling is needed I get a following error
Error
TypeError: Cannot read property 'primaryColor' of undefined
Code
HTML: <div class="container-fluid" style="background-color:<%=user.branding.primaryColor%>;">
Route:
router.get("/:username", function (req, res) {
User.find({ username: req.params.username}, function (err, foundUser) {
if(empty(foundUser)){
res.render("error", {err:"the user " +req.params.username + " does not exist "})
} else {
if (err) {
console.log("Oh no error: ", err)
}
Link.find().where('author.id').equals(foundUser._id).exec(function (err, foundLinks) {
if (err) {
console.log("Oh no error 2: ", err);
}
res.render('dashboard/preview', {
user: foundUser,
links: foundLinks,
});
});
}
});
});
foundUser:
[
{
links: { link: [] },
settings: { accountIsAccountActive: true, darkMode: false },
branding: {
primaryColor: '#D46975',
secondaryColor: '#9646C8',
image: 'https://i.ya-webdesign.com/images/default-image-png-1.png',
linkRadius: '15px',
linkColor: '#FFFFFF'
},
_id: 5eef79490e264c,
firstname: 'testy',
lastname: 'test',
username: 'test',
__v: 0
}
]
I am starting to feel like this may not be possible, thank you in advance for the help!
foundUser is an array. In your HTML code, you need to use
user[0].branding.primaryColor
Or
change mongo query from
User.find()
to
User.findOne()
Or
Assign foundUser[0] to user.
res.render('dashboard/preview', {
user: foundUser[0],
links: foundLinks,
});
Related
I'm using GraphQL with Meteor and Pup v2, and I have a problem accessing the users data via a special ID provided to every user on signup, this ID will be used in a link (mysite.com/user/specialId) so other users can view the searched users account. Problem is, I can't get the data with the special ID, I can't get any data back if I don't pass in the users _id provided by MongoDB. Below I have a bunch of the code used:
Attempt 1
I tried to use a custom on-the-go way just to be able to at least access the data to see if it works (and then implement it correctly later)
const GET_USER_DETAILS = gql`
query user($userId: String) {
user(userId: $userId) {
userId
username
_id
}
}
`;
Here I export so I can get the data:
export default compose(
graphql(GET_USER_DETAILS, {
options: ({ match }) => ({
fetchPolicy: 'no-cache',
variables: {
// existing specialId for testing purposes, to be replaced with match.params.userId
userId: "J4xZzvvhBDSEufnBn",
},
}),
}),
)(PublicProfileView);
This returns a 400 error Network error: Response not successful: Received status code 400 error and after multiple attempts, I could not fix it, so I tried a different approach...
Attempt 2
I tried to go deep into the files and change the GraphQL. Created a new query:
query userById($userId: String) {
userById(userId: $userId) {
...UserAttributes
}
}
(Mentioned fragment)
fragment UserAttributes on User {
_id
name {
...
}
username
emailAddress
oAuthProvider
roles {
...
}
settings {
...
}
userId
}
Tried to add new item in API:
type Query {
...
userById(userId: String): User
...
}
Resolver:
resolvers: {
Query: {
...
userById: (parent, args) => {
// Assuming args equals an object like { _id: '123' };
return UserQueries.userById(args);
},
},
},
query.js, attempt 1:
userById: (parent) => queryUsers.find({ userId: parent.userId }, { sort: { createdAt: 1 } }).fetch()
Attempt 2:
userById: (parent, args, context) => {
return queryUsers({
userId: parent.userId,
});
},
And finally
Attempt 3
I tried to modify the get query
const getQueryModified = (options) => {
// console.log(options.userId)
try {
return options.userId
? { 'userId': options.userId }
: { userId: options.userId };
} catch (exception) {
throw new Error(`[queryUsers.getQuery] ${exception.message}`);
}
};
Here is the original query I tried to modify:
const getQuery = (options) => {
try {
return options.search
? {
_id: { $ne: options.currentUser._id },
$or: [
{ 'profile.name.first': options.search },
{ 'profile.name.last': options.search },
{ 'emails.address': options.search },
// { 'userId': options.search },
{ 'services.facebook.first_name': options.search },
{ 'services.facebook.last_name': options.search },
{ 'services.facebook.email': options.search },
],
}
: { _id: options.currentUser._id };
} catch (exception) {
throw new Error(`[queryUsers.getQuery] ${exception.message}`);
}
};
Unfortunately this was also unsuccessful, the best I get from these when executing the below query is null...
userById(userId: "J4xZzvvhBDSEufnBn"){
username
}
All I want is to get the user data from their userId and not their _id, but I can't seem to figure out how to do it
I'm working a project developing by Meteor.js & now I'm working for a validation something like that
import SimpleSchema from 'simpl-schema';
const CompanySchema = new SimpleSchema({
company_name: {
type: String,
min: 5,
max: 50,
label: "Company Name"
}
});
Company.attachSchema(CompanySchema);
but in the console showing like below image
but when trying to keep the "Error" like this way
console.log(err.Error);
it's showing
undefined
here is insert functionalities
Company.insert(
{
company_name: inputs.companyName.value,
},
function(err) {
if (err) {
console.log(err);
} else {
console.log('Inserted successfully');
}
}
);
what's the issue actually.
Thanks
When your client-side Mongo insert fails it produces a native Error. If you log it's name, message and stack it shows the expected properties of an Error:
Company.insert(
{
company_name: inputs.companyName.value,
},
function(err) {
if (err) {
console.log(err.name);
console.log(err.message);
console.log(err.stack);
}
}
);
Produces:
Error
Company Name must be at least 5 characters in company insert
Error: Company Name must be at least 5 characters in company insert
at getErrorObject (collection2.js:498)
at doValidate (collection2.js:470)
at Collection.Mongo.Collection.(:3000/anonymous function) [as insert] (http://localhost:3000/packages/aldeed_collection2.js?hash=9ed657993899f5a7b4df81355fd11d6b77396b85:286:14)
at Blaze.TemplateInstance.helloOnCreated (main.js:10)
at blaze.js?hash=51f4a3bdae106610ee48d8eff291f3628713d847:3398
at Function.Template._withTemplateInstanceFunc (blaze.js?hash=51f4a3bdae106610ee48d8eff291f3628713d847:3769)
at fireCallbacks (blaze.js?hash=51f4a3bdae106610ee48d8eff291f3628713d847:3394)
at Blaze.View.<anonymous> (blaze.js?hash=51f4a3bdae106610ee48d8eff291f3628713d847:3474)
at fireCallbacks (blaze.js?hash=51f4a3bdae106610ee48d8eff291f3628713d847:2014)
at Object.Tracker.nonreactive (tracker.js:603)
The attribute err.error in contrast is part of the Meteor.Error, which is thrown if the insert fails inside a Meteor Method.
This would be the case for example in such code:
Meteor.call('someInserMethod', { company_name: 'abc' }, (err, res) => {
console.log(err) // this error is a Meteor.Error
})
In GraphiQL at http://localhost:8080/graphiql, I'm using this query:
{
instant_message(fromID: "1"){
fromID
toID
msgText
}
}
I'm getting this response:
{
"data": {
"instant_message": {
"fromID": null,
"toID": null,
"msgText": null
}
},
"errors": [
{
"message": "Resolve function for \"instant_message.fromID\" returned undefined",
"locations": [
{
"line": 3,
"column": 5
}
]
},
{
"message": "Resolve function for \"instant_message.toID\" returned undefined",
"locations": [
{
"line": 4,
"column": 5
}
]
},
{
"message": "Resolve function for \"instant_message.msgText\" returned undefined",
"locations": [
{
"line": 5,
"column": 5
}
]
}
]
}
I tried to set up my system according to the examples found here:
https://medium.com/apollo-stack/tutorial-building-a-graphql-server-cddaa023c035#.s7vjgjkb7
Looking at that article, it doesn't seem to be necessary to set up individual resolvers for string fields, but I must be missing something.
What is the correct way to update my resolvers so as to return results from string fields? Example code would be greatly appreciated!
Thanks very much in advance to all for any thoughts or info.
CONNECTORS
import Sequelize from 'sequelize';
//SQL CONNECTORS
const db = new Sequelize(Meteor.settings.postgres.current_dev_system.dbname, Meteor.settings.postgres.current_dev_system.dbuser, Meteor.settings.postgres.current_dev_system.dbpsd, {
host: 'localhost',
dialect: 'postgres',
});
db
.authenticate()
.then(function(err) {
console.log('Connection to Sequelize has been established successfully.');
})
.catch(function (err) {
console.log('Unable to connect to the Sequelize database:', err);
});
const IMModel = db.define('IM', {
id: {type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true},
fromID: {type: Sequelize.STRING},
toID: {type: Sequelize.STRING},
msgText: {type: Sequelize.STRING}
});
IMModel.sync({force: true}).then(function () {
// Table created
return IMModel.create({
fromID: '1',
toID: '2',
msgText: 'msg set up via IMModel.create'
});
});
const IM = db.models.IM;
export {db, IM };
SCHEMA
const typeDefinitions = [`
type instant_message {
id: Int
fromID: String
toID: String
msgText: String
}
type Query {
instant_message(fromID: String, toID: String, msgText: String): instant_message
}
type RootMutation {
createInstant_message(
fromID: String!
toID: String!
msgText: String!
): instant_message
}
schema {
query: Query,
mutation: RootMutation
}
`];
export default typeDefinitions;
RESOLVERS
import * as connectors from './db-connectors';
import { Kind } from 'graphql/language';
const b = 100;
const resolvers = {
Query: {
instant_message(_, args) {
const a = 100;
return connectors.IM.find({ where: args });
}
},
RootMutation: {
createInstant_message: (__, args) => { return connectors.IM.create(args); },
},
};
export default resolvers;
When you define your GraphQLObjectTypes you need to provide a resolver for each of their fields.
You defined your instant_message with multiple fields but did not provide resolvers for each of these fields.
More over you defined the types of those field with regular typescript fields while you need to define it with GraphQL types (GraphQLInt, GraphQLString, GrapQLFloat etc..)
So defining your type should look something like this:
let instant_message = new GraphQLObjectType({
id: {
type: GraphQLInt,
resolve: (instantMsg)=> {return instantMsg.id}
}
fromID: {
type: GraphQLString,
resolve: (instantMsg)=> {return instantMsg.fromID}
}
toID: {
type: GraphQLString,
resolve: (instantMsg)=> {return instantMsg.toID}
}
msgText: {
type: GraphQLString,
resolve: (instantMsg)=> {return instantMsg.msgText}
}
})
In addition, you will need to define your Query as follows:
let Query = new GraphQLObjectType({
name: "query",
description: "...",
fields: () => ({
instant_messages: {
type: new GraphQLList(instant_message),
args: {
id: {type: GraphQLInt}
},
resolve: (root, args) => {
connectors.IM.find({ where: args })
}
}
})
})
The issue is that the query does not expect an array,
Please fix it:
type Query {
instant_message(fromID: String, toID: String, msgText: String): [instant_message]
}
Then you should make sure the resolver returns Array of objects, if it doesnt work then the resolver is not returning an Array.
I cant get SEO settings to work on a route basis.
What I've tried:
1) Setting it globally in seotest.js above client or server code.
SeoCollection = new Meteor.Collection("SeoCollection");
Router.route('/', function () {
this.render('index');
SeoCollection.update(
{
route_name: 'index'
},
{
$set: {
route_name: 'index',
title: 'indexpagetestl',
meta: {
'description': 'Manuel Schoebel is an experienced web developer and startup founder. He develops but also consults startups about internet topics.'
},
og: {
'title': 'About - Manuel Schoebel',
'image': 'http://manuel-schoebel.com/images/authors/manuel-schoebel.jpg'
}
}
},
{
upsert: true
}
);
Router.route('/notindex', function () {
this.render('notindex');
SeoCollection.update(
{
route_name: 'notindex'
},
{
$set: {
route_name: 'notindex',
title: 'notindexpagetestl',
meta: {
'description': 'Manuel Schoebel is an experienced web developer and startup founder. He develops but also consults startups about internet topics.'
},
og: {
'title': 'About - Manuel Schoebel',
'image': 'http://manuel-schoebel.com/images/authors/manuel-schoebel.jpg'
}
}
},
{
upsert: true
}
);
}
I've also tried to same code inside (Meteor.isClient) and (Meteor.isServer) code, but neither works.
I am able to get the initial SEO meta tags working with:
Meteor.startup(function() {
if(Meteor.isClient){
return SEO.config({
title: 'Manuel Schoebel - MVP Development',
meta: {
'description': 'Manuel Schoebel develops Minimal Viable Producs (MVP) for Startups'
},
og: {
'image': 'http://manuel-schoebel.com/images/authors/manuel-schoebel.jpg'
}
});
}
});
I have an autocomplete on a text box which shows zipcode, City, State. Currently when I start typing zipcode [e.g. 55414] the autocomplete works and starts to show the relevant zip,city and State. But I can't figure out how to trigger autocomplete if I start typing a city name. I want both of these triggers on the textbox. I tried to add another rule in the rules array but it doesn't work. ZipCodes collection has _id, city, state fields. _id is zipcode.
Template.search.helpers({
settings : function () {
return {
position: "bottom",
limit: 20,
rules: [{
collection: ZipCodes,
field: "_id",
template: Template.userPill
}]
}
}
Thanks in advance
I think you are using meteor-autocomplete
In that case you can use selector option
Template.search.helpers({
settings : function () {
return {
position: "bottom",
limit: 20,
rules: [{
collection: ZipCodes,
field: "_id",
template: Template.userPill,
selector: function(match) {
var regex;
regex = new RegExp(match, 'i');
return {
$or: [
{
'_id': regex
}, {
'city': regex
}
]
};
},
}]
}
}
})
I know this answer is too late for you, but it can be helpful to somebody in the future. Just do this inside your server-side publish function.
Meteor.publish('ZipCodesPublication', function(selector, options) {
let limitTo = Math.abs(options.limit) > 50 ? 50 : options.limit,
defaultSelector = selector._id,
regEx = defaultSelector.$regex,
regExOptions = defaultSelector.$options,
customSeletor = {
$or: [
{
city: {
$regex: regEx,
$options: regExOptions
}
},
{
_id: {
$regex: regEx,
$options: regExOptions
}
}
]
};
Autocomplete.publishCursor(Clients.find(customSeletor), this);
this.ready();
});
And just do this on the client:
Template.search.helpers({
settings : function () {
return {
position: "bottom",
limit: 20,
rules: [{
collection: 'ZipCodes',
subscription: 'ZipCodesPublication',
field: "_id",
template: Template.userPill
}]
}
}