Using predefined model data in Keystonejs partials views - javascript

Currently, I created a keystone model as following format:
var keystone = require('keystone');
var SiteSettings = new keystone.List('SiteSetting', {
map: { name: 'siteName' },
nocreate: true,
noedit: false,
nodelete: true,
singular:'SiteSetting',
plural: 'SiteSetting',
});
SiteSettings.add({
siteName: { type: String, required: true },
contactNumber: { type: String, required: false },
facebookGroupUrl: { type: String, required: false },
googlePlusUrl: { type: String, required: false }
});
SiteSettings.register();
Then I went to keystone back-end, created a new Site Setting object.
And on my default template, i am using a partial view like this:
<body>
<main>
{{>header}}
{{>footer}}
</main>
</body>
And this is my footer partial:
<div class="row">//I want to print my site name here</div>
But I have no idea how can retrieve model data without a route. Because it's a partial view.
Any idea ? what should I do ? Is there anything I can do in middleware.js
Thank you everyone,.

Yes, you can load the global site settings in a middleware.
// routes/middleware.js
exports.initLocals = (req, res, next) => {
const { locals } = res;
// Load site settings from db
keystone.list('SiteSettings').model.findOne().exec((err, result) => {
locals.siteSetting = result;
next(err);
});
};
// routes/index.js
const { initLocals } = require('./middleware');
keystone.pre('routes', initLocals);
Then you can use the siteName in the footer.
<div class="row">{{ siteSetting.siteName }}</div>

Related

how to solve Trying to get property 'bids' of non-object error

I want to display data from bid table in a form of datatable. But I get this error
"Trying to get property 'bids' of non-object" if it doesn't have bids.The bids model is connected to auction model and the auction model is connected to media site model. How to make it display blank record if it doesn't have data.
Here is my controller:
<?php
namespace App\Http\Controllers;
use App\Auction;
use App\Bid;
use App\User;
use App\Media;
use App\MediaSite;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class MediaSiteController extends Controller
{
public function show(MediaSite $mediaSite)
{
$auction = $mediaSite->auction;
$bids = $auction->bids;
return view('admin.media-site.show', ['mediaSite' => $mediaSite,'auction' => $auction], compact('auction'));
}
My view:
<body>
<div id="datatable-bid"></div>
</body>
<script>
$(document).ready(function () {
var datatableBid = $('#datatable-bid').mDatatable({
// datasource definition
data: {
type: 'local',
source: {!! json_encode($auction->bids) !!},
pageSize: 10
},
// layout definition
layout: {
theme: 'default', // datatable theme
class: '', // custom wrapper class
scroll: false,
footer: false // display/hide footer
},
// column sorting
sortable: true,
pagination: true,
search: {
input: $('#panel-search')
},
// columns definition
columns: [
{
field: "price",
title: "Price",
}, {
field: "month",
title: "Month",
},{
field: "user_id",
title: "User Id",
}
]
});
</script>
Here is my error:
Trying to get property 'bids' of non-object
place following after $auction = $mediaSite->auction;
if($auction){
$bids = $auction->bids;
}else{
//put following line or whatever you need to do if there is no data comes
$auction = [];
}
In the show() function make these changes
$auction = $mediaSite->auction;
if($auction) {
$bids = $auction->bids;
} else {
$bids = [];
}
// now send $bids to view along with $auction
// may be like this
// return view(..., compact($auction, $bids));
Then, in your view make this change
// datasource definition
data: {
type: 'local',
source: {!! json_encode($bids) !!},
pageSize: 10
},
See if this helps.

adding data to array of existing object into mongodb from form

I have my route below that takes the form data and tries to input the page and archive into an existing name that is already in the mongodb. My form data is being sent correctly as I can see from my console.log.
Now I need to insert the page name and archive name where it equals name. Whether it already has data or not. They are already setup with array in the schema. You can see my schema below
Any ideas on how to get this setup?
router.post('/add-page', function(req, res, next){
if(req.body.name && req.body.page && req.body.archive){
//create object with form input
var pageData = {
client: req.body.name,
page: req.body.page,
archive: req.body.archive
};
console.log(pageData);
//insert data
Page.then(function(db){
delete req.body._id;
db.collection('pages').insertOne();
});
return res.render('index', { title: 'Home' });
}else{
var err = new Error('All fields required.');
err.status = 400;
return next(err);
}
});
var ClientSchema = new mongoose.Schema({
client: {
type: String,
required: true,
trim: true,
unique: true,
},
page: {
type: [],
trim: true,
},
archive: {
type: [],
trim: true,
}
});

keystone.js : how can I display content from 2 different models on my index page

I am working with keystone.js on a Project. And I am doing Templating with Handlebars(hbs)
What I want to do: On my index page I want to display a slider(solved this with unslider.js so I only need to be able to display the images and text from slider model) and the 3 newest events(That works).
Here is my code so far:
This is my Event Model
var keystone = require('keystone');
var Types = keystone.Field.Types;
/**
* Event Model
* ==========
*/
var Event = new keystone.List('Event', {
map: { name: 'title' },
autokey: { path: 'slug', from: 'title', unique: true },
});
Event.add({
title: { type: String, required: true },
state: { type: Types.Select, options: 'draft, published, archived', default: 'draft', index: true },
author: { type: Types.Relationship, ref: 'User', index: true },
publishedDate: { type: Types.Date, index: true, dependsOn: { state: 'published' } },
image: { type: Types.CloudinaryImage },
content: {
brief: { type: Types.Html, wysiwyg: true, height: 150 },
extended: { type: Types.Html, wysiwyg: true, height: 400 },
},
eventcategories: { type: Types.Relationship, ref: 'EventCategory', many: true },
});
Event.schema.virtual('content.full').get(function () {
return this.content.extended || this.content.brief;
});
Event.defaultColumns = 'title, state|20%, author|20%, publishedDate|20%';
Event.register();
And this my slider Model
var keystone = require('keystone');
var Types = keystone.Field.Types;
/**
* slider Model
* ==========
*/
var Slider = new keystone.List('Slider', {
map: { name: 'title' },
autokey: { path: 'slug', from: 'title', unique: true },
});
Slider.add({
title: { type: String, required: true },
image: { type: Types.CloudinaryImage },
});
Slider.register();
Both models work correctly in the backend and it should only be a problem in the view... so here come index view
var keystone = require('keystone');
exports = module.exports = function (req, res) {
var view = new keystone.View(req, res);
var locals = res.locals;
// Init locals
locals.section = 'eventblog';
locals.filters = {
eventcategory: req.params.category,
};
// Set locals
locals.section = 'slider';
locals.data = {
titles: [], //maybe this is a problem?
images: [], //maybe this is a problem?
events: [],
eventcategories: [],
}
// locals.section is used to set the currently selected
// item in the header navigation.
locals.section = 'home';
view.on('init', function (next) {
var q = keystone.list('Event').paginate({
page: req.query.page || 1,
perPage: 3,
maxPages: 1,
filters: {
state: 'published',
},
})
.sort('-publishedDate')
.populate('author categories');
if (locals.data.eventcategory) {
q.where('categories').in([locals.data.eventcategory]);
}
q.exec(function (err, results) {
locals.data.events = results;
next(err);
});
});
// Render the view
view.render('index');
};
And here is my index.hbs
<div class="container">
<div class="my-slider">
<ul>
{{#each slider}}
<!-- doesn't loop even once-->
<li>
<img src="{{cloudinaryUrl image width='300' height='300'}}" >
<p>{{title}}</p>
</li>
{{/each}}
</ul>
</div>
<!-- the code below works correctly -->
<div class="events row">
{{# each data.events.results}}
<div class="col-md-4 col-lg-4">
<h3>{{{title}}}</h3>
<p class=" text-muted">{{{categoryList categories prefix="Posted in "}}}
{{#if author.name.first}}by {{author.name.first}}{{/if}}
</p>
{{#if image}}<img src="{{{cloudinaryUrl image height=160 crop='fit' }}}" class="img center-block">{{/if}}
<p>{{{content.brief}}}</p>
{{#if content.extended}}<p class="read-more">Read more...</p>{{/if}}
</div>
{{/each}}
</div>
</div>
I really hope that my question is clear and someone can help me
The code in your route sets locals.data.events which is why you can use it from handlebars. However, you're not setting locals.slider which is why that {{#each slider}} loop doesn't execute.
In your route, you also need to do something like
keystone.list('Slider').model.find().exec(function (err, results) {
locals.sliders = restuls;
next(err);
}
which populates locals.slider so that in you can do {{#each slider}} in your hbs template. The rest of your code should then work fine.
(Disclaimer, I've not actually tested this, but it should work. If not, try and work out what happened. There are plenty of examples of this kind of code in the keystone demo project)

Issues with dynamic routing using meteor-autoform and iron:router

What I am trying to do is create a form with meteor-autoform that will redirect the user to a newly generated route on submit. My thought process is that I can take the submissions _id and use it for an iron:router parameter. What I have so far looks as followed:
Creation of Form
Submits = new Meteor.Collection('Submits');
Submits.allow({
insert: function(username, doc){
return !!username;
}
});
SubmitSchema = new SimpleSchema({
title: {
type: String,
label: "Title"
},
subject:{
type: String,
label: "Subject"
},
summary:{
type: String,
label: "Summary"
},
author:{
type: String,
label: "Author",
autoValue: function() {
return this.userId
},
autoform: {
type: "hidden"
}
},
createdAt: {
type: Date,
label: "Created At",
autoValue: function(){
return new Date()
},
autoform: {
type: "hidden"
}
}
});
Submits.attachSchema( SubmitSchema );
Routing
Router.route('/submit', {
layoutTemplate: 'submitLayout',
waitOn: function() { return Meteor.subscribe("Submits"); },
loadingTemplate: 'loading'
});
Router.route('/submit/:_id', {
name: 'formDisplay',
data: function() {
return Submits.findOne({this.params._id});
}
});
And then I just have the average publish and find calls. My issues are I'm not sure how to perform the redirect on submit, and I am not sure how to display the form results on the newly generated route.
Any help would be appreciated.
I was able to do it by adding an autoform.hook and changing my routing a bit.
Autoform hook:
AutoForm.addHooks('insertSubmit', {
onSuccess: function(doc) {
Router.go('formDisplay',{_id: this.docId});
}
})
Routing:
Router.route('/submit/:_id', {
name: 'submitLayout',
data: function() { return Products.findOne(this.params._id);}
});
I got this information from this post:
Route to the new data submitted by Meteor autoform using iron router?

Mongoose findOne callback not working

Mongoose findOne function call does nothing and I am in trouble again. Callback is not never returned...
schema.js file:
var schemaSizeGroup = new Schema({
sizeGroupId : {type: Number, required: true, index: true, index: { unique: true }}
,sizeGroupName : {type: String, required: true, trim: true, index: { unique: true }}
,sizeGroupValues : {type: String, required: true, trim: true }
,active : {type: Boolean, default: true }
}, { collection: 'sizegroup' }).index({sizeGroupId : 1});
module.exports ={
SizeGroup : mongoose.connection.model('SizeGroup', schemaSizeGroup),
}
index.js file:
findDocumentById : function(sGroupId, callback){
winston.info(" Trying to select!");
model.SizeGroup.findOne( {sizeGroupId : sGroupId} ,function(err, sGroup) {
winston.info(" Select done:");
winston.info(JSON.stringify(sGroup,null,2));
if(!err) {
if(!sGroup) {
callback(new Error(" No SizeObject Found for Id:" + sizeGroupId));
} else { callback(null, sGroup); }
}
else {
callback(err);
}
});
}
}
selectin data using mongo client returns correct data nicely:
db.sizegroup.find({sizeGroupId : 6});
When using mongoose.set('debug', true) output looks like:
Mongoose: sizegroup.findOne({ sizeGroupId: 6 }) { fields: undefined }
I have active mongoose connection, because all the previous insert statements have been successful.
Am I doing something wrong?
It was a callback problem in program flow. Clear case of pure stupidity....

Categories

Resources