Customizable Meteor Navbar with Orion CMS

Written by Pete Corey on Mar 2, 2015.

Last week I talked about building a dictionary driven category system for articles using the fantastic Orion CMS. This week I’m going to continue in that same vein by building a fully customizable navbar!

So what’s the plan of attack? In Orion, we’ll define an entity called pages. This entity will hold the title and content for a variety of pages that will exist on our site. We want to be able to choose a selection of these pages to appear on our navbar in a specified order. We’ll keep that list of pages in an Orion dictionary.

Defining the Pages Entity

The first step is to define the pages entity that will be used by our application. This will be a straight-forward Orion entity:

orion.addEntity('pages', {
    title: {
        type: String,
        label: 'Title'
    },
    content: {
        type: String,
        label: 'Content',
        autoform: {
            afFieldInput: {
                type: 'froala',
                inlineMode: false,
            }
        }
    }
}, {
    icon: 'bookmark',
    sidebarName: 'Pages',
    pluralName: 'Pages',
    singularName: 'Page',
    tableColumns: [
        {
            data: 'title',
            title: 'Title'
        },
        orion.attributeColumn('froala', 'content', 'Preview')
    ]
});

Defining the Page Order

The next step is to define an Orion dictionary entry to hold the list of pages as they will appear in the navbar:

orion.admin.addAdminSubscription(orion.subs.subscribe('entity', 'pages'));

orion.dictionary.addDefinition('pages.$', 'config', {
    type: String,
    label: 'Page',
    optional: false,
    autoform: {
        type: 'select',
        options: function() {
            return orion.entities.pages.collection.find().fetch().map(function(page) {
                return {
                    value: page._id,
                    label: page.title
                };
            });
        }
    }
});

orion.dictionary.addDefinition('pages', 'config', {
    type: Array,
    minCount: 1,
    optional: false,
    label: 'Page Order'
});

There are a few moving parts here. Let’s break them down to get a better understanding of what’s going on.

Building Our Orion Interface

The first thing to notice is that our page order dictionary entry actually consists of two entries: pages and pages.$. Our goal is to have the page order list be a list of selections populated with pages entities. This means that pages must be an Array type. The children of pages (pages.$) are given the type String. When using Orion, it’s required that you add the definition for child dictionary entries (pages.$) before adding the parent (pages).

Populating Our Selects

In order to build the navbar, we need to be able to select which pages will appear from the set of all pages in the system. This means that we need to have the options of our pages.$ attribute driven by the pages entity collection. How do we do this?

Just like last time, the answer is to provide a custom options function. Our options function will fetch all of the documents in the pages entity collection and transform them into select options:

options: function() {
    return orion.entities.pages.collection.find().fetch().map(function(page) {
        return {
            value: page._id,
            label: page.title
        };
    });
}

If you were to visit your Orion dashboard at this point, you may notice that your page order selects aren’t populating with data (or maybe they are, if you visited the entities page first). This is because we haven’t subscribed to the pages entity collection yet. The final piece to this puzzle is to add a new subscription to the admin dashboard:

orion.admin.addAdminSubscription(orion.subs.subscribe('entity', 'pages'));

And that’s it! We now have a system where we can create pages in our CMS, and choose which of those pages will appear in our navbar. Check out the nav tag on my hello-orion Github project to see a working example.

Custom Categories with Meteor's Orion CMS

Written by Pete Corey on Feb 23, 2015.

Lately I’ve been playing with Orion, the fantastic Meteor based CMS. The way Orion builds on top of aldeed:collection2 and aldeed:autoform to create an incredibly flexible and powerful CMS is inspiring.

One feature I wanted out of Orion was the ability to have data from the dictionary be accessible from within an entity. For example, I wanted to keep a list of Categories in Orion’s dictionary and associate each Article entity with one of these categories. After doing a little digging, I found a way to accomplish this.

I’ve created a gist to show off this functionality. The key lines of code are shown below:

allowedValues: function() {
    return orion.dictionary.collection.findOne()['categories'];
},
autoform: {
    options: function() {
        return orion.dictionary.collection.findOne()['categories'].map(function(value) {
            return {
                value: value,
                label: value
            };
        });
    }
}

When setting up your entity’s attributes, you’ll need to add custom allowedValues and autoform functions. The allowedValues function returns the possible string values that can be saved into this field. These values are pulled from the categories field of the dictionary document. autoform is used to build the select options presented to the user. In this case, we’re using the category string as both the value and the label.

Interestingly, if allowedValues is not a function, it will build the options automatically. However, if allowedValues is a function, the dropdown will be empty. We need to explicitly specify a autoform.options function to build our options for us. I haven’t looked into what’s causing this.

These are issues with this approach. If a user creates an article with a certain category, but then deletes that category from the dictionary, the article will still hold the deleted value in its category field. When that article is edited in Orion, the category field will be blank. I’m hoping to spend a little more time in the future to address these issues and dig deeper into this kind of Orion functionality.

Meteor and Mongod.lock

Written by Pete Corey on Feb 16, 2015.

When Mongo closes incorrectly, (due to things like crashes, hard reboots, etc…), it leaves behind a non-zero byte mongod.lock file. The presence of this file indicates that Mongo wasn’t cleaned up correctly and will prevent Mongo from starting normally.

In a Meteor project, meteor will fail with the following messages if it detects that Mongo was not correctly shut down:

=> Started proxy.
Unexpected mongo exit code 100. Restarting.
Unexpected mongo exit code 100. Restarting.
Unexpected mongo exit code 100. Restarting.
Can't start Mongo server.
MongoDB had an unspecified uncaught exception.
This can be caused by MongoDB being unable to write to a local database.
Check that you have permissions to write to .meteor/local. MongoDB does
not support filesystems like NFS that do not allow file locking.

To fix this, two things need to happen. First, remove the lock file:

% rm .meteor/local/db/mongod.lock

Not that the lock file is deleted, Meteor should start without any complaints from Mongo. To be safe, Mongo’s repair routine should be run on your Meteor database. Normally, this is done using a mongod command (mongod --repair), but since Meteor doesn’t use mongod, we need to kick off the repair from within the Mongo shell:

% meteor mongo
> db.repairDatabase()
{ “ok” : 1}

That’s it! You can read more about how to recover data after an unexpected shutdown in the Mongo docs.