Skip to content

Commit

Permalink
Up to and including 9: Errors
Browse files Browse the repository at this point in the history
  • Loading branch information
dovadi committed Mar 23, 2015
1 parent 5e5ec00 commit 49eb332
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 11 deletions.
18 changes: 18 additions & 0 deletions client/helpers/errors.js
@@ -0,0 +1,18 @@
Errors = new Mongo.Collection(null);

throwError = function(message) {
Errors.insert({message: message});
};

Template.errors.helpers({
errors: function() {
return Errors.find();
}
});

Template.error.rendered = function() {
var error = this.data;
Meteor.setTimeout(function () {
Errors.remove(error._id);
}, 3000);
};
1 change: 1 addition & 0 deletions client/templates/application/layout.html
@@ -1,6 +1,7 @@
<template name="layout">
<div class="container">
{{> header}}
{{> errors}}
<div id="main">
{{> yield}}
</div>
Expand Down
14 changes: 14 additions & 0 deletions client/templates/includes/errors.html
@@ -0,0 +1,14 @@
<template name="errors">
<div class="errors">
{{#each errors}}
{{> error}}
{{/each}}
</div>
</template>

<template name="error">
<div class="alert alert-danger" role="alert">
<button type="button" class="close" data-dismiss="alert">&times;</button>
{{message}}
</div>
</template>
10 changes: 6 additions & 4 deletions client/templates/posts/post_edit.html
@@ -1,15 +1,17 @@
<template name="postEdit">
<form class="main form page">
<div class="form-group">
<div class="form-group" {{errorClass 'url'}}>
<label class="control-label" for="url">URL</label>
<div class="controls">
<input name="url" id="url" type="text" value="{{url}}" placeholder="Your URL" class="form-control"/>
<input name="url" id="url" type="text" value="{{url}}" placeholder="Your URL" class="form-control"/>
<span class="help-block">{{errorMessage 'url'}}</span>
</div>
</div>
<div class="form-group">
<div class="form-group" {{errorClass 'title'}}>
<label class="control-label" for="title">Title</label>
<div class="controls">
<input name="title" id="title" type="text" value="{{title}}" placeholder="Name your post" class="form-control"/>
<input name="title" id="title" type="text" value="{{title}}" placeholder="Name your post" class="form-control"/>
<span class="help-block">{{errorMessage 'title'}}</span>
</div>
</div>
<input type="submit" value="Submit" class="btn btn-primary submit"/>
Expand Down
19 changes: 18 additions & 1 deletion client/templates/posts/post_edit.js
@@ -1,3 +1,15 @@
Template.postEdit.created = function() {
Session.set('postEditErrors', {});
}
Template.postEdit.helpers({
errorMessage: function(field) {
return Session.get('postEditErrors')[field];
},
errorClass: function (field) {
return !!Session.get('postEditErrors')[field] ? 'has-error' : '';
}
});

Template.postEdit.events({
'submit form': function(e) {
e.preventDefault();
Expand All @@ -9,13 +21,18 @@ Template.postEdit.events({
title: $(e.target).find('[name=title]').val()
}

var errors = validatePost(postProperties);
if (errors.title || errors.url)
return Session.set('postEditErrors', errors);


//Here we directly update the collection on the client side whereas
//for the creation of a Post we use a Server Method. See chapter 8 on Method Calls vs Client-side Data Manipulation
//See https://www.discovermeteor.com/blog/meteor-methods-client-side-operations/
Posts.update(currentPostId, {$set: postProperties}, function(error) {
if (error) {
// display the error to the user
alert(error.reason);
throwError(error.reason);
} else {
Router.go('postPage', {_id: currentPostId});
}
Expand Down
10 changes: 6 additions & 4 deletions client/templates/posts/post_submit.html
@@ -1,15 +1,17 @@
<template name="postSubmit">
<form class="main form page">
<div class="form-group">
<div class="form-group" {{errorClass 'url'}}>
<label class="control-label" for="url">URL</label>
<div class="controls">
<input name="url" id="url" type="text" value="" placeholder="Your URL" class="form-control"/>
<input name="url" id="url" type="text" value="" placeholder="Your URL" class="form-control"/>
<span class="help-block">{{errorMessage 'url'}}</span>
</div>
</div>
<div class="form-group">
<div class="form-group" {{errorClass 'title'}}>
<label class="control-label" for="title">Title</label>
<div class="controls">
<input name="title" id="title" type="text" value="" placeholder="Name your post" class="form-control"/>
<input name="title" id="title" type="text" value="" placeholder="Name your post" class="form-control"/>
<span class="help-block">{{errorMessage 'title'}}</span>
</div>
</div>
<input type="submit" value="Submit" class="btn btn-primary"/>
Expand Down
21 changes: 19 additions & 2 deletions client/templates/posts/post_submit.js
@@ -1,3 +1,16 @@
Template.postSubmit.created = function() {
Session.set('postSubmitErrors', {});
}

Template.postSubmit.helpers({
errorMessage: function(field) {
return Session.get('postSubmitErrors')[field];
},
errorClass: function (field) {
return !!Session.get('postSubmitErrors')[field] ? 'has-error' : '';
}
});

Template.postSubmit.events({
'submit form': function(e) {
e.preventDefault();
Expand All @@ -7,15 +20,19 @@ Template.postSubmit.events({
title: $(e.target).find('[name=title]').val()
};

var errors = validatePost(post);
if (errors.title || errors.url)
return Session.set('postSubmitErrors', errors);

Meteor.call('postInsert', post, function(error, result) {

// display the error to the user and abort
if (error)
return alert(error.reason);
return throwError(error.reason);

// show this result but route anyway
if (result.postExists)
alert('This link has already been posted');
return throwError('This link has already been posted');

Router.go('postPage', {_id: result._id});
});
Expand Down
26 changes: 26 additions & 0 deletions lib/collections/posts.js
Expand Up @@ -5,6 +5,28 @@ Posts.allow({
remove: function(userId, post) { return ownsDocument(userId, post); }
});

Posts.deny({
update: function(userId, post, fieldNames) {
// may only edit the following two fields:
return (_.without(fieldNames, 'url', 'title').length > 0);
}
});

Posts.deny({
update: function(userId, post, fieldNames, modifier) {
var errors = validatePost(modifier.$set);
return errors.title || errors.url;
}
});

validatePost = function (post) {
var errors = {};
if (!post.title)
errors.title = "Please fill in a headline";
if (!post.url)
errors.url = "Please fill in a URL";
return errors;
}

Meteor.methods({
postInsert: function(postAttributes) {
Expand All @@ -14,6 +36,10 @@ Meteor.methods({
url: String
});

var errors = validatePost(postAttributes);
if (errors.title || errors.url)
throw new Meteor.Error('invalid-post', "You must set a title and URL for your post");

var postWithSameLink = Posts.findOne({url: postAttributes.url});
if (postWithSameLink) {
return {
Expand Down

0 comments on commit 49eb332

Please sign in to comment.