Merge pull request #1820 from b-d-m-p/master

Added comments from the example-simple video tutorial for reference f…
This commit is contained in:
Sacha Greif 2018-01-20 11:03:40 +09:00 committed by GitHub
commit db8c148d89
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 168 additions and 56 deletions

View file

@ -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

View file

@ -1 +1,2 @@
// client/main.js #tutorial-step-3 - This is the file that is called into package.js.
import '../modules/index.js';

View file

@ -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}) =>
<div style={{maxWidth: '500px', margin: '20px auto'}}>
{
/* 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
}) => (
<div style={{ maxWidth: "500px", margin: "20px auto" }}>
{/* 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... */}
<Helmet>
<link name="bootstrap" rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css"/>
<link
name="bootstrap"
rel="stylesheet"
type="text/css"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css"
/>
</Helmet>
{/* user accounts */}
<div style={{padding: '20px 0', marginBottom: '20px', borderBottom: '1px solid #ccc'}}>
<div
style={{
padding: "20px 0",
marginBottom: "20px",
borderBottom: "1px solid #ccc"
}}
>
{/* ...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... */}
<Components.AccountsLoginForm />
</div>
{loading ?
<Components.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 ? (
<Components.Loading />
) : (
<div className="movies">
{/* 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) ?
<div style={{marginBottom: '20px', paddingBottom: '20px', borderBottom: '1px solid #ccc'}}>
{Movies.options.mutations.new.check(currentUser) ? (
<div
style={{
marginBottom: "20px",
paddingBottom: "20px",
borderBottom: "1px solid #ccc"
}}
>
<h4>Insert New Document</h4>
<Components.SmartForm collection={Movies} />
</div> :
null
}
<Components.SmartForm collection={Movies} />
</div>
) : null}
{/* documents list */}
{/* documents list - this is another small utility in Vulcan and it will display it as a card... */}
{results.map(movie => <Components.Card fields={['name', 'year', 'review']} key={movie._id} collection={Movies} document={movie} currentUser={currentUser} />)}
{/* load more */}
{results.map(movie => (
<Components.Card
fields={["name", "year", "review"]}
key={movie._id}
collection={Movies}
document={movie}
currentUser={currentUser}
/>
))}
{totalCount > results.length ?
<a href="#" onClick={e => {e.preventDefault(); loadMore();}}>Load More ({count}/{totalCount})</a> :
{/* load more - this is the load more button. On click we trigger the loadMore function which is passed as a prop by withList... */}
{totalCount > results.length ? (
<a
href="#"
onClick={e => {
e.preventDefault();
loadMore();
}}
>
Load More ({count}/{totalCount})
</a>
) : (
<p>No more items.</p>
}
)}
</div>
}
)}
</div>
);
// ...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!

View file

@ -1,3 +1,6 @@
// modules/index.js - #tutorial-step-8 -
// This is where we import our collections
// The Movies collection
import './movies/collection.js';

View file

@ -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.

View file

@ -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;

View file

@ -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' });

View file

@ -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';

View file

@ -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.
*/

View file

@ -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');