Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edit and delete jobs asynchronously #6

Merged
merged 12 commits into from
Nov 1, 2014
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ Once you have SQLite3 working, you can set up your development environment with
│   │   ├── main.css # our custom CSS
│   │   └── normalize.css # a commonly used CSS library to aid in cross-browser compatibility
│   └── js # folder to hold JavaScript script files
│   └── main.js # our main JavaScript script file, all the JS stuff goes here
│   └── jobs.js # script to manage behavior relating to job resources
│   └── skills.js # script to manage behavior relating to skills resources
└── views # a folder to hold the HTML templates for our pages
├── layout.erb # this is the main template for our site
├── partials # a folder containing a bunch of partials (not listed, because there are a bunch of them)
Expand Down Expand Up @@ -96,11 +97,12 @@ This is the first release with JavaScript and jQuery included. As a reference, h

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

- [ ] User can edit jobs on the résumé show page
- [ ] User can delete jobs on the résumé show page
- [ ] Editing and deleting jobs occurs asynchronously
- [ ] Edited jobs are updated on the page without refresh
- [ ] Deleted jobs are removed from the page without refresh
- [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

Expand Down
27 changes: 25 additions & 2 deletions linkedout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ def default_user
job.save

if request.xhr?
partial :'partials/job', :locals => { :job => job }
html = "<li>"
html += partial :'partials/job', :locals => { :job => job }
html += partial :'partials/job_edit', :locals => { :job => job, :hidden => true }
html += "</li>"
html
else
redirect "/"
end
Expand All @@ -62,7 +66,26 @@ def default_user
job = Job.get(job_id)
job.update(job_attrs)

redirect "/"
if request.xhr?
partial :'partials/job', :locals => { :job => job }
else
redirect "/"
end
end

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

job_id = job_attrs.delete("id")

job = Job.get(job_id)
job.destroy

if request.xhr?
job_id
else
redirect "/"
end
end

post "/skills" do
Expand Down
10 changes: 10 additions & 0 deletions public/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ form.mini input[type="submit"] { float: right; }
padding: 0;
}

.float_right {
float: right;
padding-left: 1em;
}

.hidden {
display: none;
visibility: hidden;
}


/*
* SECTION STYLING
Expand Down
121 changes: 121 additions & 0 deletions public/js/jobs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// A utility function to log information to the console
var log = function(message) {
var timestamp = (new Date()).toTimeString();
console.log('[' + timestamp + '] ' + message);
};

var createJobOnSubmit = function() {
$('.jobs').on('submit', 'form[name="new_job"]', function(evt) {
log("New job form submitted");

evt.preventDefault();

var $newJobForm = $(this);
var newJobFormData = $(this).serialize();

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

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

log("Adding new job element to list");
$newJobForm.parent('li').before(jobHTML);

$newJobForm.get(0).reset();
});
});
};

var showEditJobFormOnClick = function() {
$('.jobs').on('click', '.js_edit_job', function(evt) {
log("Show edit job form link clicked");

evt.preventDefault();

var $jobElem = $(this).parent('.job');
var $editJobForm = $jobElem.siblings('form[name="edit_job"]');

log("Hiding job element and showing job form");
$jobElem.addClass('hidden');
$editJobForm.removeClass('hidden');
});
};

var updateJobOnSubmit = function() {
$('.jobs').on('submit', 'form[name="edit_job"]', function(evt) {
log("Edit job form submitted");

evt.preventDefault();

var $editJobForm = $(this);
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");

// Send async PUT request to /jobs/edit
$.ajax({
url: '/jobs/edit',
type: 'PUT',
data: editJobFormData
}).done(function(responseData) {
log("Received response from PUT request to /jobs/edit");
// This function will execute when the response comes
// back from the server
//
// We expect to receive the updated job HTML
// (as a <div> element with job info inside)
var newJobHTML = responseData;

log("Hiding job form and showing job element");
$jobElem.removeClass('hidden');
$editJobForm.addClass('hidden');

log("Replacing old job info with updated info");
$jobElem.replaceWith(newJobHTML);
});
});
};

var deleteJobOnSubmit = function() {
$('.jobs').on('submit', 'form[name="delete_job"]', function(evt) {
log("Edit job form submitted");

evt.preventDefault();

var $deleteJobForm = $(this);
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");

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

log("Removing deleted job element");
$jobContainerElem.remove();
});
});
};

$(document).ready(function() {
createJobOnSubmit();

showEditJobFormOnClick();
updateJobOnSubmit();

deleteJobOnSubmit();
});
27 changes: 0 additions & 27 deletions public/js/main.js → public/js/skills.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,35 +47,8 @@ var insertNewSkillIntoDOM = function(newSkillHTML) {
$newSkillForm.get(0).reset();
};


var createNewJobsOnSubmit = function() {
var $newJobForm = getNewJobForm();

$newJobForm.submit(function (evt) {
evt.preventDefault();

var jobFormData = $(this).serialize();

$.post("/jobs", jobFormData, insertNewJobIntoDOM);
});
};

var getNewJobForm = function() {
return $('form[name="new_job"]');
};

var insertNewJobIntoDOM = function(newJobHTML) {
var $newJobForm = getNewJobForm();

$newJobForm.parent('li').before(newJobHTML);

$newJobForm.get(0).reset();
};


// Wait to execute all code until the document is ready
// (i.e. all of the DOM nodes have been loaded)
$(document).ready(function() {
createNewSkillsOnSubmit();
createNewJobsOnSubmit();
});
3 changes: 2 additions & 1 deletion views/layout.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.js"></script>

<!-- Load own scripts -->
<script type="text/javascript" src="/js/main.js"></script>
<script type="text/javascript" src="/js/jobs.js"></script>
<script type="text/javascript" src="/js/skills.js"></script>
</body>
<html>
10 changes: 8 additions & 2 deletions views/partials/job.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
<li>
<div class="job">
<form name="delete_job" action="/jobs" 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>
<h4><%= job.job_title %> at <%= job.company_name %></h4>
<p><%= job.job_description %></p>
</li>
</div>
34 changes: 15 additions & 19 deletions views/partials/job_edit.erb
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
<%
# When rendering a partial, the collection item takes the name
# of the file for the item, so the job object is assigned to
# the local variable `job_form`
job = job_edit
%>
<li>
<form name="edit_job" action="/jobs/edit" method="post" accept-charset="utf-8">
<input type="hidden" name="_method" value="put">
<% if hidden %>
<form class="hidden" name="edit_job" action="/jobs/edit" method="post" accept-charset="utf-8">
<% else %>
<form name="edit_job" action="/jobs/edit" 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="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>
<input type="text" name="job[job_title]" value="<%= job.job_title %>"> at
<input type="text" name="job[company_name]" value="<%= job.company_name %>">
<br>

<label for="job[job_description]">Job Description</label><br>
<textarea name="job[job_description]"><%= job.job_description %></textarea>
<br>
<label for="job[job_description]">Job Description</label><br>
<textarea name="job[job_description]"><%= job.job_description %></textarea>
<br>

<input type="submit" value="Save">
</form>
</li>
<input type="submit" value="Save">
</form>
20 changes: 9 additions & 11 deletions views/partials/job_new.erb
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
<li>
<form name="new_job" action="/jobs" method="post" accept-charset="utf-8">
<input type="text" name="job[job_title]" placeholder="Job title"> at
<input type="text" name="job[company_name]" placeholder="Company name">
<br>
<form name="new_job" action="/jobs" method="post" accept-charset="utf-8">
<input type="text" name="job[job_title]" placeholder="Job title"> at
<input type="text" name="job[company_name]" placeholder="Company name">
<br>

<label for="job[job_description]">Job Description</label><br>
<textarea name="job[job_description]">Your life story goes here. Keep it concise.</textarea>
<br>
<label for="job[job_description]">Job Description</label><br>
<textarea name="job[job_description]">Your life story goes here. Keep it concise.</textarea>
<br>

<input type="submit" value="Add job">
</form>
</li>
<input type="submit" value="Add job">
</form>
6 changes: 5 additions & 1 deletion views/resumes/edit.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
<section class="jobs two_thirds">
<h2>Jobs</h2>
<ul class="no_bullets no_padding">
<%= partial :'partials/job_edit', collection: @jobs %>
<% @jobs.each do |job| %>
<li>
<%= partial :'partials/job_edit', :locals => { :job => job, :hidden => false } %>
</li>
<% end %>
</ul>
</section>

Expand Down
11 changes: 9 additions & 2 deletions views/resumes/show.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,16 @@
<section class="jobs two_thirds">
<h2>Jobs</h2>
<ul class="no_bullets no_padding">
<%= partial :'partials/job', collection: @jobs %>
<% @jobs.each do |job| %>
<li>
<%= partial :'partials/job', :locals => { :job => job } %>
<%= partial :'partials/job_edit', :locals => { :job => job, :hidden => true } %>
<li>
<% end %>

<%= partial :'partials/job_new' %>
<li>
<%= partial :'partials/job_new' %>
</li>
</ul>
</section>

Expand Down