Page is not rendering

Asked

Viewed 83 times

0

I am configuring a web application using Keystone JS.

I set up some Routes, and views, and also already set up a "virtual store" structure to add and exlcuir sightseeing tours.

The problem, that due to some configuration, the site is not rendering the page correctly.

The following message appears:

Sorry, an error occurred loading the page (500)

/home/pedromagalhaes/Projects/Project_ag2/templates/views/tours.Pug:8 6| . Row 7|

8| if ! date.Tour 9| H2 Invalid tour 10| Else 11|

Cannot read Property 'Tour' of Undefined

Some codes from my application.

**

Archive: Models/Tour.js

var keystone = require('keystone');
var Types = keystone.Field.Types;

/**
 * User Tour
 * ==========
 */

 var Tour = new keystone.List('Tour', {
        autokey: { from: 'nome_do_passeio', path: 'key', unique: true, Singular:'Passeio', Plural: 'Passeios'},
 });

 Tour.add({
   nome_do_passeio: {type: String, label:"Nome do Passeio", initial:true},
   image: { type: Types.CloudinaryImage },
   category: { type: Types.Select, options: 'barco, vinícola', label:"Categoria", initial:true},
     custo: { type: Types.Money, format: '$0.0,00', label:"Valor", initial:true },
     data_do_passeio: { type: Types.Date, yearRange:(2000,2100), format: ('Do MMMM YYYY'), default: Date.now, label:"Data do Passeio", initial:true },
     descricao_passeio: {  type: Types.Html, wysiwyg: true, height: 200, label: "Descrição do Passeio"},
   incluido: {  type: Types.Html, wysiwyg: true, height: 200, label: "O que está incluído"},
   cidade: { type: String, required: false, index: true, label:"Cidade" }
 });


 Tour.defaultSort = Tour.data_do_passeio;
 Tour.defaultColumns = 'nome_do_passeio, custo, cidade, category, data_do_passeio';
 Tour.register();

**

File: Routes/index.js

/**
 * This file is where you define your application routes and controllers.
 *
 * Start by including the middleware you want to run for every request;
 * you can attach middleware to the pre('routes') and pre('render') events.
 *
 * For simplicity, the default setup for route controllers is for each to be
 * in its own file, and we import all the files in the /routes/views directory.
 *
 * Each of these files is a route controller, and is responsible for all the
 * processing that needs to happen for the route (e.g. loading data, handling
 * form submissions, rendering the view template, etc).
 *
 * Bind each route pattern your application should respond to in the function
 * that is exported from this module, following the examples below.
 *
 * See the Express application routing documentation for more information:
 * http://expressjs.com/api.html#app.VERB
 */

var keystone = require('keystone');
var middleware = require('./middleware');
var importRoutes = keystone.importer(__dirname);

// Common Middleware
keystone.pre('routes', middleware.initLocals);
keystone.pre('render', middleware.flashMessages);

// Import Route Controllers
var routes = {
    views: importRoutes('./views'),
};

// Setup Route Bindings
exports = module.exports = function (app) {
    // Views
    app.get('/', routes.views.index);
    app.get('/blog/:category?', routes.views.blog);
    app.get('/blog/post/:post', routes.views.post);
    app.get('/gallery', routes.views.gallery);
    app.get('/tours', routes.views.tours);
    app.get('/tours/:tour', routes.views.tour);
    app.all('/contact', routes.views.contact);

    // NOTE: To protect a route so that only admins can see it, use the requireUser middleware:
    // app.get('/protected', middleware.requireUser, routes.views.protected);

};

**

File: Helpers/index.js

var moment = require('moment');
var _ = require('underscore');
var hbs = require('handlebars');
var keystone = require('keystone');
var cloudinary = require('cloudinary');

// Collection of templates to interpolate
var linkTemplate = _.template('<a href="<%= url %>"><%= text %></a>');
var scriptTemplate = _.template('<script src="<%= src %>"></script>');
var cssLinkTemplate = _.template('<link href="<%= href %>" rel="stylesheet">');

module.exports = function () {

    var _helpers = {};

    /**
     * Generic HBS Helpers
     * ===================
     */

    // standard hbs equality check, pass in two values from template
    // {{#ifeq keyToCheck data.myKey}} [requires an else blockin template regardless]
    _helpers.ifeq = function (a, b, options) {
        if (a == b) { // eslint-disable-line eqeqeq
            return options.fn(this);
        } else {
            return options.inverse(this);
        }
    };

    /**
     * Port of Ghost helpers to support cross-theming
     * ==============================================
     *
     * Also used in the default keystonejs-hbs theme
     */

    // ### Date Helper
    // A port of the Ghost Date formatter similar to the keystonejs - jade interface
    //
    //
    // *Usage example:*
    // `{{date format='MM YYYY}}`
    // `{{date publishedDate format='MM YYYY'`
    //
    // Returns a string formatted date
    // By default if no date passed into helper than then a current-timestamp is used
    //
    // Options is the formatting and context check this.publishedDate
    // If it exists then it is formated, otherwise current timestamp returned

    _helpers.date = function (context, options) {
        if (!options && context.hasOwnProperty('hash')) {
            options = context;
            context = undefined;

            if (this.publishedDate) {
                context = this.publishedDate;
            }
        }

        // ensure that context is undefined, not null, as that can cause errors
        context = context === null ? undefined : context;

        var f = options.hash.format || 'MMM Do, YYYY';
        var timeago = options.hash.timeago;
        var date;

        // if context is undefined and given to moment then current timestamp is given
        // nice if you just want the current year to define in a tmpl
        if (timeago) {
            date = moment(context).fromNow();
        } else {
            date = moment(context).format(f);
        }
        return date;
    };

    // ### Category Helper
    // Ghost uses Tags and Keystone uses Categories
    // Supports same interface, just different name/semantics
    //
    // *Usage example:*
    // `{{categoryList categories separator=' - ' prefix='Filed under '}}`
    //
    // Returns an html-string of the categories on the post.
    // By default, categories are separated by commas.
    // input. categories:['tech', 'js']
    // output. 'Filed Undder <a href="blog/tech">tech</a>, <a href="blog/js">js</a>'

    _helpers.categoryList = function (categories, options) {
        var autolink = _.isString(options.hash.autolink) && options.hash.autolink === 'false' ? false : true;
        var separator = _.isString(options.hash.separator) ? options.hash.separator : ', ';
        var prefix = _.isString(options.hash.prefix) ? options.hash.prefix : '';
        var suffix = _.isString(options.hash.suffix) ? options.hash.suffix : '';
        var output = '';

        function createTagList (tags) {
            var tagNames = _.pluck(tags, 'name');

            if (autolink) {
                return _.map(tags, function (tag) {
                    return linkTemplate({
                        url: ('/blog/' + tag.key),
                        text: _.escape(tag.name),
                    });
                }).join(separator);
            }
            return _.escape(tagNames.join(separator));
        }

        if (categories && categories.length) {
            output = prefix + createTagList(categories) + suffix;
        }
        return new hbs.SafeString(output);
    };

    /**
     * KeystoneJS specific helpers
     * ===========================
     */

    // block rendering for keystone admin css
    _helpers.isAdminEditorCSS = function (user, options) {
        var output = '';
        if (typeof (user) !== 'undefined' && user.isAdmin) {
            output = cssLinkTemplate({
                href: '/keystone/styles/content/editor.min.css',
            });
        }
        return new hbs.SafeString(output);
    };

    // block rendering for keystone admin js
    _helpers.isAdminEditorJS = function (user, options) {
        var output = '';
        if (typeof (user) !== 'undefined' && user.isAdmin) {
            output = scriptTemplate({
                src: '/keystone/js/content/editor.js',
            });
        }
        return new hbs.SafeString(output);
    };

    // Used to generate the link for the admin edit post button
    _helpers.adminEditableUrl = function (user, options) {
        var rtn = keystone.app.locals.editable(user, {
            list: 'Post',
            id: options,
        });
        return rtn;
    };

    // ### CloudinaryUrl Helper
    // Direct support of the cloudinary.url method from Handlebars (see
    // cloudinary package documentation for more details).
    //
    // *Usage examples:*
    // `{{{cloudinaryUrl image width=640 height=480 crop='fill' gravity='north'}}}`
    // `{{#each images}} {{cloudinaryUrl width=640 height=480}} {{/each}}`
    //
    // Returns an src-string for a cloudinary image

    _helpers.cloudinaryUrl = function (context, options) {

        // if we dont pass in a context and just kwargs
        // then `this` refers to our default scope block and kwargs
        // are stored in context.hash
        if (!options && context.hasOwnProperty('hash')) {
            // strategy is to place context kwargs into options
            options = context;
            // bind our default inherited scope into context
            context = this;
        }

        // safe guard to ensure context is never null
        context = context === null ? undefined : context;

        if ((context) && (context.public_id)) {
            options.hash.secure = keystone.get('cloudinary secure') || false;
            var imageName = context.public_id.concat('.', context.format);
            return cloudinary.url(imageName, options.hash);
        }
        else {
            return null;
        }
    };

    // ### Content Url Helpers
    // KeystoneJS url handling so that the routes are in one place for easier
    // editing.  Should look at Django/Ghost which has an object layer to access
    // the routes by keynames to reduce the maintenance of changing urls

    // Direct url link to a specific post
    _helpers.postUrl = function (postSlug, options) {
        return ('/blog/post/' + postSlug);
    };

    // Direct url link to a specific product
    _helpers.tourUrl = function (tourSlug, options) {
        return ('/tour/' + tourSlug);
    };

    // might be a ghost helper
    // used for pagination urls on blog
    _helpers.pageUrl = function (pageNumber, options) {
        return '/blog?page=' + pageNumber;
    };

    // create the category url for a blog-category page
    _helpers.categoryUrl = function (categorySlug, options) {
        return ('/blog/' + categorySlug);
    };

    // ### Pagination Helpers
    // These are helpers used in rendering a pagination system for content
    // Mostly generalized and with a small adjust to `_helper.pageUrl` could be universal for content types

    /*
    * expecting the data.posts context or an object literal that has `previous` and `next` properties
    * ifBlock helpers in hbs - http://stackoverflow.com/questions/8554517/handlerbars-js-using-an-helper-function-in-a-if-statement
    * */
    _helpers.ifHasPagination = function (postContext, options) {
        // if implementor fails to scope properly or has an empty data set
        // better to display else block than throw an exception for undefined
        if (_.isUndefined(postContext)) {
            return options.inverse(this);
        }
        if (postContext.next || postContext.previous) {
            return options.fn(this);
        }
        return options.inverse(this);
    };

    _helpers.paginationNavigation = function (pages, currentPage, totalPages, options) {
        var html = '';

        // pages should be an array ex.  [1,2,3,4,5,6,7,8,9,10, '....']
        // '...' will be added by keystone if the pages exceed 10
        _.each(pages, function (page, ctr) {
            // create ref to page, so that '...' is displayed as text even though int value is required
            var pageText = page;
            // create boolean flag state if currentPage
            var isActivePage = ((page === currentPage) ? true : false);
            // need an active class indicator
            var liClass = ((isActivePage) ? ' class="active"' : '');

            // if '...' is sent from keystone then we need to override the url
            if (page === '...') {
                // check position of '...' if 0 then return page 1, otherwise use totalPages
                page = ((ctr) ? totalPages : 1);
            }

            // get the pageUrl using the integer value
            var pageUrl = _helpers.pageUrl(page);
            // wrapup the html
            html += '<li' + liClass + '>' + linkTemplate({ url: pageUrl, text: pageText }) + '</li>\n';
        });
        return html;
    };

    // special helper to ensure that we always have a valid page url set even if
    // the link is disabled, will default to page 1
    _helpers.paginationPreviousUrl = function (previousPage, totalPages) {
        if (previousPage === false) {
            previousPage = 1;
        }
        return _helpers.pageUrl(previousPage);
    };

    // special helper to ensure that we always have a valid next page url set
    // even if the link is disabled, will default to totalPages
    _helpers.paginationNextUrl = function (nextPage, totalPages) {
        if (nextPage === false) {
            nextPage = totalPages;
        }
        return _helpers.pageUrl(nextPage);
    };


    //  ### Flash Message Helper
    //  KeystoneJS supports a message interface for information/errors to be passed from server
    //  to the front-end client and rendered in a html-block.  FlashMessage mirrors the Jade Mixin
    //  for creating the message.  But part of the logic is in the default.layout.  Decision was to
    //  surface more of the interface in the client html rather than abstracting behind a helper.
    //
    //  @messages:[]
    //
    //  *Usage example:*
    //  `{{#if messages.warning}}
    //      <div class="alert alert-warning">
    //          {{{flashMessages messages.warning}}}
    //      </div>
    //   {{/if}}`

    _helpers.flashMessages = function (messages) {
        var output = '';
        for (var i = 0; i < messages.length; i++) {

            if (messages[i].title) {
                output += '<h4>' + messages[i].title + '</h4>';
            }

            if (messages[i].detail) {
                output += '<p>' + messages[i].detail + '</p>';
            }

            if (messages[i].list) {
                output += '<ul>';
                for (var ctr = 0; ctr < messages[i].list.length; ctr++) {
                    output += '<li>' + messages[i].list[ctr] + '</li>';
                }
                output += '</ul>';
            }
        }
        return new hbs.SafeString(output);
    };


    //  ### underscoreMethod call + format helper
    //  Calls to the passed in underscore method of the object (Keystone Model)
    //  and returns the result of format()
    //
    //  @obj: The Keystone Model on which to call the underscore method
    //  @undescoremethod: string - name of underscore method to call
    //
    //  *Usage example:*
    //  `{{underscoreFormat enquiry 'enquiryType'}}

    _helpers.underscoreFormat = function (obj, underscoreMethod) {
        return obj._[underscoreMethod].format();
    };

    return _helpers;
};

**

Archive: Views/Tours.

extends ../layouts/default

block content

    .container.col-md-12.col-lg-12
        .row

            if !data.Tour
                h2 Passeio inválido
            else

                - var qtd_nome_do_passeio = data.Tour
                each tr in qtd_nome_do_passeio
                    .col-md-4.col-lg-4
                        h2= tr.nome_do_passeio
                            if tr.image.exists
                                .image-wrap: img(src=tr._.image.scale(450,200)).img-responsive
                        p Cidade #{tr.cidade} / Categoria #{tr.category}
                        p Custo: R$: #{tr.custo},00
  • Are you sure you should use data.Tour and not only Tour? What gives p= JSON.stringify(data) if you test a page with only this line?

  • I did p= JSON.stringify(date), but I didn’t print anything out. I don’t think he’s inheriting the class. But I couldn’t figure out why.

  • Going by parts, what gives it: p= [typeof data, typeof Tour].join('|')?

  • Imprimiu: Undefined|Undefined

  • This is bad :) There is something missing in the Node. Where is the req.render()? It’s yours or Keystone’s?

  • It’s from Keystone itself. Unfortunately I looked in the project for the expression "req.render" and there is no.

  • There is the function: view.render('tours'); One is on tour.js, and another tours.js

  • Try to pass view.render('tours', {foo: 123}); and see if anything gets to Pug.

Show 3 more comments
No answers

Browser other questions tagged

You are not signed in. Login or sign up in order to post.