diff --git a/.meteor/packages b/.meteor/packages
index e2ab627d9..526f0e58f 100644
--- a/.meteor/packages
+++ b/.meteor/packages
@@ -14,6 +14,9 @@ accounts-password@1.4.0
############ Your Packages ############
+#tutorial-step-1 - You can follow along with the video here: http://docs.vulcanjs.org/example-simple.html
+# This is where you enable packages.
+
example-simple
# example-movies
# example-instagram
diff --git a/packages/example-simple/lib/client/main.js b/packages/example-simple/lib/client/main.js
index ae6ea31db..cd505610f 100644
--- a/packages/example-simple/lib/client/main.js
+++ b/packages/example-simple/lib/client/main.js
@@ -1 +1,2 @@
+// client/main.js #tutorial-step-3 - This is the file that is called into package.js.
import '../modules/index.js';
diff --git a/packages/example-simple/lib/components/movies/MoviesList.jsx b/packages/example-simple/lib/components/movies/MoviesList.jsx
index 7101f2a18..ff9ce6418 100644
--- a/packages/example-simple/lib/components/movies/MoviesList.jsx
+++ b/packages/example-simple/lib/components/movies/MoviesList.jsx
@@ -1,8 +1,13 @@
/*
-List of movies.
+components/MoviesList.jsx #tutorial-step-7 -
+The component for our list of movies, which we called in to modules/routes.js.
+
Wrapped with the "withList" and "withCurrentUser" containers.
+#tutorial-step-11 -
+Now, we are going to look at this in a bit more detail.
+This component is a React component. We only have one but it does a bunch of things...
*/
import React from 'react';
@@ -11,57 +16,109 @@ import { Components, withList, withCurrentUser, registerComponent } from 'meteor
import Movies from '../../modules/movies/collection.js';
-const MoviesList = ({results = [], currentUser, loading, loadMore, count, totalCount}) =>
-
-
-
+{
+ /* These are "props". They are variables for the component that are passed by the components parent.
+ In this case, to create the parent we wrapped the component in "Higer Order Compoents" (See the Higer Order Compoents section below.)
+ By doing this, we can pass on those props to the children of he HOCs and give them access to the props... */
+}
+const MoviesList = ({
+ results = [],
+ currentUser,
+ loading,
+ loadMore,
+ count,
+ totalCount
+}) => (
+
+ {/* First, this is a Helment tag. It's a React package that loads head tags. We're using it to load the Bootstrap stylesheet.
+ This is not Vulcan specific but it is an easy way to add tags to the head... */}
-
+
{/* user accounts */}
-
-
+
+ {/* ...This is the log in form component. It allowed you to create an account in our web app.
+ It takes care of all accounts stuff like changing passwords, signing in and out, and so on
+ Just pop this in anywhere you want to use it. It's in the Vulcan accounts package... */}
-
- {loading ?
-
- :
-
+ {/* ... We have a test for the loding variable (See the "Higher Order Components" section at the bottom and then the "props" section at the top.)... */}
+ {loading ? (
+
+ ) : (
-
- {/* new document form */}
+ {/* new document form - this if for inserting new documents. Because the collection has the schema, when we generate the form, it know what the colleciton should look like
+ You only need to specify the colleciton. You don't need to code any of the form. Validation will work and it will show you fields based on your user permission...*/}
- {Movies.options.mutations.new.check(currentUser) ?
-
+);
+// ...this is where we specify how to load the data in the options object that we pass to withList
+// if you want, you can specify many more options here, like how often to look for data or what fields to query from, filtering and sorting options. ...
const options = {
collection: Movies,
limit: 5,
};
+// These two functions (withList & withCurrentUser) are Higher Order Components (HOC) and by wrapping our component with this we can give it "props". (See the "props" section at the top.)
registerComponent('MoviesList', MoviesList, withCurrentUser, [withList, options]);
+
+
+// #tutorial-step-12 - Well. that's it! If you like this, go on to the movies-example, where we get more granular when it comes to data loading.
+// Well thanks for tuning in! Come visit us at our chat room at slack.vulcanjs.org. See you soon!
diff --git a/packages/example-simple/lib/modules/index.js b/packages/example-simple/lib/modules/index.js
index 05f9c6f50..f3b30a31a 100644
--- a/packages/example-simple/lib/modules/index.js
+++ b/packages/example-simple/lib/modules/index.js
@@ -1,3 +1,6 @@
+// modules/index.js - #tutorial-step-8 -
+// This is where we import our collections
+
// The Movies collection
import './movies/collection.js';
diff --git a/packages/example-simple/lib/modules/movies/collection.js b/packages/example-simple/lib/modules/movies/collection.js
index 085da13f3..7ffff832b 100644
--- a/packages/example-simple/lib/modules/movies/collection.js
+++ b/packages/example-simple/lib/modules/movies/collection.js
@@ -1,6 +1,9 @@
/*
-The main Movies collection definition file.
+modules/movies/collection.js - #tutorial-step-9 -
+This is the main Movies collection definition file.
+
+A collection in VulcanJS is basically is a model, a type of data, like posts, comments, or users.
*/
@@ -12,17 +15,30 @@ import schema from './schema.js';
Movies collection definition
+We create a new collection with the createCollection function
*/
const Movies = createCollection({
+ // It takes the collection name...
collectionName: 'Movies',
+ // ...the type name, which is it's name of that type's singular instance
+ // usually it is the same as the collection name but singular.
+ // It comes in useful when it is time to build our GraphQL schema...
typeName: 'Movie',
+ // ...this is a JS schema, not GraphQL...
schema,
+ // ...then our default resolvers and default mutations...
+
+ // A resolver is the thing that gives you data, that fetches it in the database and sends it to the client.
+ // There are three default resolvers: list - for a list of documents, single - for a single document, and total - for the total number of documents that match a given query.
+ // You can code your own too. Check out the next example, the movies example to do so...
resolvers: getDefaultResolvers('Movies'),
+ // A mutation is the act of changing data on the server.
+ // There are three default mutaitons: inserting a new document, editing an existing document, and removing a document. You can only do this if you own it.
mutations: getDefaultMutations('Movies'),
});
@@ -31,8 +47,11 @@ const Movies = createCollection({
Permissions for members (regular users)
+...members are default users in Vulcan...
+
*/
const membersActions = [
+ // ...these are the actions that members can do...
'movies.new',
'movies.edit.own',
'movies.remove.own',
@@ -43,13 +62,22 @@ Users.groups.members.can(membersActions);
Default sort
+This is the default sort view for this data type...
+
*/
Movies.addDefaultView(terms => ({
options: {
sort: {
+ // ...We want to order by when it was created.
+ // This gets passed to MongoDB.
+ // This will insert in the same order on the server and the client,
+ // which is how the app knew where to put our new Jaws 14 entry in the page.
createdAt: -1
}
}
}));
export default Movies;
+
+// There were three things I mentioned that you might not have heard of:
+// schema, revolvers, and mutations. I will talk about them in the next steps.
diff --git a/packages/example-simple/lib/modules/movies/schema.js b/packages/example-simple/lib/modules/movies/schema.js
index bec9dc1ef..9ac92c2d2 100644
--- a/packages/example-simple/lib/modules/movies/schema.js
+++ b/packages/example-simple/lib/modules/movies/schema.js
@@ -1,22 +1,24 @@
/*
+modules/movies/schema.js - #tutorial-step-10 -
+This is a JS object that defines every property of a collection document...
+
A SimpleSchema-compatible JSON schema
*/
const schema = {
-
// default properties
_id: {
type: String,
optional: true,
- viewableBy: ['guests'],
+ viewableBy: ["guests"]
},
createdAt: {
type: Date,
optional: true,
- viewableBy: ['guests'],
+ viewableBy: ["guests"],
onInsert: (document, currentUser) => {
return new Date();
}
@@ -24,45 +26,50 @@ const schema = {
userId: {
type: String,
optional: true,
- viewableBy: ['guests'],
+ viewableBy: ["guests"],
resolveAs: {
- fieldName: 'user',
- type: 'User',
+ fieldName: "user",
+ type: "User",
resolver: (movie, args, context) => {
- return context.Users.findOne({ _id: movie.userId }, { fields: context.Users.getViewableFields(context.currentUser, context.Users) });
+ return context.Users.findOne(
+ { _id: movie.userId },
+ { fields: context.Users.getViewableFields(context.currentUser, context.Users) }
+ );
},
addOriginalField: true
}
},
-
+
// custom properties
name: {
- label: 'Name',
+ label: "Name",
type: String,
optional: true,
- viewableBy: ['guests'],
- insertableBy: ['members'],
- editableBy: ['members'],
+ // ...these next three are interesting—they take a user group that says which group can do what action.
+ // ...guests are anonymous users...
+ viewableBy: ["guests"],
+ /// ...members can only edit documents that they own. This is part of the default mutations. Back to modules/movies/collection.js...
+ insertableBy: ["members"],
+ editableBy: ["members"]
},
year: {
- label: 'Year',
+ label: "Year",
type: String,
optional: true,
- viewableBy: ['guests'],
- insertableBy: ['members'],
- editableBy: ['members'],
+ viewableBy: ["guests"],
+ insertableBy: ["members"],
+ editableBy: ["members"]
},
review: {
- label: 'Review',
+ label: "Review",
type: String,
optional: true,
- control: 'textarea',
- viewableBy: ['guests'],
- insertableBy: ['members'],
- editableBy: ['members']
- },
-
+ control: "textarea",
+ viewableBy: ["guests"],
+ insertableBy: ["members"],
+ editableBy: ["members"]
+ }
};
export default schema;
diff --git a/packages/example-simple/lib/modules/routes.js b/packages/example-simple/lib/modules/routes.js
index 5236bbf3c..b532e7ae3 100644
--- a/packages/example-simple/lib/modules/routes.js
+++ b/packages/example-simple/lib/modules/routes.js
@@ -1,5 +1,11 @@
+// modules/routes.js #tutorial-step-6 -
+// Thi is the file that is called into package.js that allows the component to be found.
+
+// First, we import this from vulcan core, which is a utility to add a new route.
import { addRoute, Components } from 'meteor/vulcan:core';
+// Then, we add the component for what we want to add.
import '../components/movies/MoviesList.jsx';
+// Next, we add the name 'movies', the path, which is the root, and the component name 'MovieList'.
addRoute({ name: 'movies', path: '/', componentName: 'MoviesList' });
diff --git a/packages/example-simple/lib/server/main.js b/packages/example-simple/lib/server/main.js
index 717ea74f3..3915b2103 100644
--- a/packages/example-simple/lib/server/main.js
+++ b/packages/example-simple/lib/server/main.js
@@ -1,2 +1,3 @@
+// server/main.js #tutorial-step-4 - This is the file that is called into package.js.
import '../modules/index.js';
import './seed.js';
\ No newline at end of file
diff --git a/packages/example-simple/lib/server/seed.js b/packages/example-simple/lib/server/seed.js
index f579bc98e..ad5db4e6f 100644
--- a/packages/example-simple/lib/server/seed.js
+++ b/packages/example-simple/lib/server/seed.js
@@ -1,6 +1,7 @@
/*
-Seed the database with some dummy content.
+server/seed.js #tutorial-step-5 -
+This is a file to seed the database with some dummy content.
*/
diff --git a/packages/example-simple/package.js b/packages/example-simple/package.js
index 4a1481df9..e8aee3c5b 100644
--- a/packages/example-simple/package.js
+++ b/packages/example-simple/package.js
@@ -1,3 +1,5 @@
+// packages.js #tutorial-step-2 - Decribes the contents of the package as well as the dependencies.
+
Package.describe({
name: 'example-simple',
});
@@ -5,6 +7,8 @@ Package.describe({
Package.onUse(function (api) {
api.use([
+
+ // Here are our dependencies:
// vulcan core
'vulcan:core@1.8.3',
@@ -17,6 +21,7 @@ Package.onUse(function (api) {
api.addFiles('lib/stylesheets/style.css');
+ // Here is the entry point for client & server:
api.mainModule('lib/server/main.js', 'server');
api.mainModule('lib/client/main.js', 'client');