Skip to content

Commit

Permalink
Merge pull request #7 from codeunion/async-delete-skills
Browse files Browse the repository at this point in the history
Asynchronously delete skills
  • Loading branch information
tannerwelsh committed Nov 2, 2014
2 parents 598af1d + cc385a7 commit 65c95b1
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 110 deletions.
21 changes: 15 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,29 @@ This is the first release with JavaScript and jQuery included. As a reference, h

### v[1.2.0] Asynchronously edit and delete jobs

[View pull request](../../pull/6).
[Download release](https://github.com/codeunion/linkedout-example/archive/v1.2.0.zip).

- [X] User can edit jobs on the résumé show page
- [X] User can delete jobs on the résumé show page
- [X] Editing jobs occurs asynchronously
- [X] Deleting jobs occurs asynchronously
- [X] Edited jobs are updated on the page without refresh
- [X] Deleted jobs are removed from the page without refresh

### v[1.4.0] Asynchronously edit and delete skills
### v[1.3.0] Asynchronously delete skills

- [X] User can delete skills on the résumé show page
- [X] Deleting skills occurs asynchronously
- [X] Deleted skills are removed from the page without refresh

This release also makes improvements to the underlying architecture of the application, including the following changes:

- [X] Use [RESTful routing](http://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services) conventions
- [X] Logging in `skills.js`
- [X] Format of HTML and JavaScript more consistent

- [ ] User can edit skills on the résumé show page
- [ ] User can delete skills on the résumé show page
- [ ] Editing and deleting skills occurs asynchronously
- [ ] Edited skills are updated on the page without refresh
- [ ] Deleted skills are removed from the page without refresh
In addition, the `/resumes/edit` page has been changed to `/users/edit` and now contains only a form to edit the user profile. This change removes redundancy in editing other resources.

### v[1.5.0] Display education information

Expand Down
37 changes: 19 additions & 18 deletions linkedout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,11 @@ def default_user
erb :'resumes/show'
end

get "/resumes/edit" do
@jobs = default_user.jobs
@skills = default_user.skills

erb :'resumes/edit'
get "/users/edit" do
erb :'users/edit'
end

put "/users/edit" do
put "/users" do
user_attrs = params[:user]

default_user.update(user_attrs)
Expand All @@ -58,11 +55,10 @@ def default_user
end
end

put "/jobs/edit" do
put "/jobs/:job_id" do
job_id = params[:job_id]
job_attrs = params[:job]

job_id = job_attrs.delete("id")

job = Job.get(job_id)
job.update(job_attrs)

Expand All @@ -73,11 +69,10 @@ def default_user
end
end

delete "/jobs" do
delete "/jobs/:job_id" do
job_id = params[:job_id]
job_attrs = params[:job]

job_id = job_attrs.delete("id")

job = Job.get(job_id)
job.destroy

Expand All @@ -96,19 +91,25 @@ def default_user
skill.save

if request.xhr? # this will return true when handling an AJAX request
partial :'partials/skill', :locals => { :skill => skill }
html = "<li>"
html += partial :'partials/skill', :locals => { :skill => skill }
html += "</li>"
html
else
redirect "/"
end
end

put "/skills/edit" do
delete "/skills/:skill_id" do
skill_id = params[:skill_id]
skill_attrs = params[:skill]

skill_id = skill_attrs.delete("id")

skill = Skill.get(skill_id)
skill.update(skill_attrs)
skill.destroy

redirect "/"
if request.xhr?
skill_id
else
redirect "/"
end
end
32 changes: 22 additions & 10 deletions public/js/jobs.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ var createJobOnSubmit = function() {
evt.preventDefault();

var $newJobForm = $(this);

// Use the destination path defined in the form's 'action'
// attribute, i.e. `/jobs`
var actionPath = $newJobForm.attr('action');
var newJobFormData = $(this).serialize();

log("Sending POST request to /jobs");
log("Sending POST request to " + actionPath);

$.post("/jobs", newJobFormData, function(jobHTML) {
log("Received response from POST request to /jobs");
$.post(actionPath, newJobFormData, function(jobHTML) {
log("Received response from POST request to " + actionPath);

log("Adding new job element to list");
$newJobForm.parent('li').before(jobHTML);
Expand Down Expand Up @@ -48,21 +52,25 @@ var updateJobOnSubmit = function() {
evt.preventDefault();

var $editJobForm = $(this);

// Use the destination path defined in the form's 'action'
// attribute, i.e. `/jobs/:job_id`
var actionPath = $editJobForm.attr('action');
var editJobFormData = $editJobForm.serialize();

// The job item to update is the the element of class
// 'job' in the same containing element (in this case, <li>)
var $jobElem = $editJobForm.siblings('.job');

log("Sending PUT request to /jobs/edit");
log("Sending PUT request to " + actionPath);

// Send async PUT request to /jobs/edit
// Send async PUT request to /jobs/:job_id
$.ajax({
url: '/jobs/edit',
url: actionPath,
type: 'PUT',
data: editJobFormData
}).done(function(responseData) {
log("Received response from PUT request to /jobs/edit");
log("Received response from PUT request to " + actionPath);
// This function will execute when the response comes
// back from the server
//
Expand All @@ -87,23 +95,27 @@ var deleteJobOnSubmit = function() {
evt.preventDefault();

var $deleteJobForm = $(this);

// Use the destination path defined in the form's 'action'
// attribute, i.e. `/jobs/:job_id`
var actionPath = $deleteJobForm.attr('action');
var deleteJobFormData = $deleteJobForm.serialize();

// Grab the containing <li> element so that we can remove
// it when the delete request completes
var $jobContainerElem = $(this).closest('li');

log("Sending DELETE request to /jobs");
log("Sending DELETE request to " + actionPath);

// Sending a DELETE request requires using the jQuery
// .ajax() function and configuring the url, type,
// data, and complete options
$.ajax({
url: '/jobs',
url: actionPath,
type: 'DELETE',
data: deleteJobFormData
}).done(function() {
log("Received response from DELETE request to /jobs");
log("Received response from DELETE request to " + actionPath);

log("Removing deleted job element");
$jobContainerElem.remove();
Expand Down
84 changes: 64 additions & 20 deletions public/js/skills.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
var createNewSkillsOnSubmit = function() {
// What's this with the dollar sign in the variable?
// It doesn't change how the variable works, it is just an
// indicator to say "this variable contains a jQuery object"
var $newSkillForm = getNewSkillForm();
// Bind to the "submit" event of the new skill form using
// event delegation
$('.skills').on('submit', 'form[name="new_skill"]', function(evt) {
log("New skill form submitted");

// Bind to the "submit" event of the new skill form
$newSkillForm.submit(function (evt) {
// Prevent the submit from sending an HTTP POST request
// Instead, we'll handle the request with AJAX
evt.preventDefault();

// What's this with the dollar sign in the variable?
// It doesn't change how the variable works, it is just an
// indicator to say "this variable contains a jQuery object"
//
// In this context, `this` points to the form which has just
// been submitted, which is what we want.
var $newSkillForm = $(this);

// Use the destination path defined in the form's 'action'
// attribute, i.e. `/skills`
var actionPath = $newSkillForm.attr('action');

// Grab the form data and serialize it as a string in
// standard URL-encoded notation
var skillFormData = $(this).serialize();
var newSkillFormData = $newSkillForm.serialize();

log("Sending POST request to " + actionPath);
// Send a POST request asynchronously to the "/skills"
// route on the server, passing the serialized form data
// in the request body.
Expand All @@ -22,33 +33,66 @@ var createNewSkillsOnSubmit = function() {
// this will send a request to the server to save this
// skill to the database
//
// The insertNewSkillIntoDOM function (argument 3) will
// The anonymous function passed as the third argument will
// be executed when the browser receives a response from
// the server. It is passed the response body, which in
// this case is a snippet of HTML representing the newly-
// created skill.
$.post("/skills", skillFormData, insertNewSkillIntoDOM);
$.post(actionPath, newSkillFormData, function(newSkillHTML) {
log("Received response from POST request to " + actionPath);

log("Adding new skill element to list");
// Add the new skill to the list, just before the form's
// parent 'li' element
$newSkillForm.parent('li').before(newSkillHTML);

log("Resetting new skill form")
// Reset the form so that new skills can be added
$newSkillForm.get(0).reset();
});
});
};

var getNewSkillForm = function() {
// Select the new skill form using its name attribute
return $('form[name="new_skill"]');
};
var deleteSkillOnSubmit = function() {
$('.skills').on('submit', 'form[name="delete_skill"]', function(evt) {
log("Edit skill form submitted");

evt.preventDefault();

var $deleteSkillForm = $(this);

// Use the destination path defined in the form's 'action'
// attribute, i.e. `/skills/:skill_id`
var actionPath = $deleteSkillForm.attr('action');
var deleteSkillFormData = $deleteSkillForm.serialize();

// Grab the containing <li> element so that we can remove
// it when the delete request completes
var $skillContainerElem = $(this).closest('li');

var insertNewSkillIntoDOM = function(newSkillHTML) {
var $newSkillForm = getNewSkillForm();
log("Sending DELETE request to " + actionPath);

// Add the new skill to the list, just before the form's
// parent 'li' element
$newSkillForm.parent('li').before(newSkillHTML);
// Sending a DELETE request requires using the jQuery
// .ajax() function and configuring the url, type,
// data, and complete options
$.ajax({
url: actionPath,
type: 'DELETE',
data: deleteSkillFormData
}).done(function() {
log("Received response from DELETE request to " + actionPath);

// Reset the form so that new skills can be added
$newSkillForm.get(0).reset();
log("Removing deleted skill element");
$skillContainerElem.remove();
});
});
};


// Wait to execute all code until the document is ready
// (i.e. all of the DOM nodes have been loaded)
$(document).ready(function() {
createNewSkillsOnSubmit();

deleteSkillOnSubmit();
});
3 changes: 1 addition & 2 deletions views/partials/job.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<div class="job">
<form name="delete_job" action="/jobs" method="post" accept-charset="utf-8" class="float_right">
<form name="delete_job" action="/jobs/<%= job.id %>" method="post" accept-charset="utf-8" class="float_right">
<input type="hidden" name="_method" value="delete">
<input type="hidden" name="job[id]" value="<%= job.id %>">
<input type="submit" value="Delete">
</form>
<a href="/resumes/edit" title="Edit job" class="js_edit_job float_right">Edit</a>
Expand Down
6 changes: 2 additions & 4 deletions views/partials/job_edit.erb
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<% if hidden %>
<form class="hidden" name="edit_job" action="/jobs/edit" method="post" accept-charset="utf-8">
<form class="hidden" name="edit_job" action="/jobs/<%= job.id %>" method="post" accept-charset="utf-8">
<% else %>
<form name="edit_job" action="/jobs/edit" method="post" accept-charset="utf-8">
<form name="edit_job" action="/jobs/<%= job.id %>" method="post" accept-charset="utf-8">
<% end %>
<input type="hidden" name="_method" value="put">

<input type="hidden" name="job[id]" value="<%= job.id %>">

<input type="text" name="job[job_title]" value="<%= job.job_title %>"> at
<input type="text" name="job[company_name]" value="<%= job.company_name %>">
<br>
Expand Down
6 changes: 5 additions & 1 deletion views/partials/skill.erb
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
<li><%= skill.name %></li>
<form name="delete_skill" action="/skills/<%= skill.id %>" method="post" accept-charset="utf-8" class="float_right">
<input type="hidden" name="_method" value="delete">
<input type="submit" value="Delete">
</form>
<%= skill.name %>
12 changes: 0 additions & 12 deletions views/partials/skill_edit.erb

This file was deleted.

10 changes: 4 additions & 6 deletions views/partials/skill_new.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<li>
<form name="new_skill" action="/skills" method="post" accept-charset="utf-8" class="mini">
<input type="text" name="skill[name]" placeholder="add a skill">
<form name="new_skill" action="/skills" method="post" accept-charset="utf-8" class="mini">
<input type="text" name="skill[name]" placeholder="add a skill">

<input type="submit" value="Save">
</form>
</li>
<input type="submit" value="Save">
</form>
28 changes: 0 additions & 28 deletions views/resumes/edit.erb

This file was deleted.

Loading

0 comments on commit 65c95b1

Please sign in to comment.