Hooking up the Scientist Removal JavaScript

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

Endpoint, done! Let's call this bad boy from JavaScript. Back in the template, each delete link will have a different URL to the endpoint. Add a new attribute called data-url set to path('genus_scientist_remove') and pass it genusId set to genus.id and userId set to genusScientist.id. Remember, that's a User object:

... lines 1 - 4
{% block body %}
<h2 class="genus-name">{{ genus.name }}</h2>
<div class="sea-creature-container">
<div class="genus-photo"></div>
<div class="genus-details">
<dl class="genus-details-list">
... lines 12 - 21
<dd>
<ul class="list-group">
{% for genusScientist in genus.genusScientists %}
<li class="list-group-item js-scientist-item">
... lines 26 - 31
<a href="#"
class="btn btn-link btn-xs pull-right js-remove-scientist-user"
data-url="{{ path('genus_scientists_remove', {
genusId: genus.id,
userId: genusScientist.id
}) }}"
>
<span class="fa fa-close"></span>
</a>
</li>
{% endfor %}
</ul>
</dd>
</dl>
</div>
</div>
<div id="js-notes-wrapper"></div>
{% endblock %}
... lines 50 - 91

Oh, and do one more thing: give the li above its own class: js-scientist-item:

... lines 1 - 4
{% block body %}
<h2 class="genus-name">{{ genus.name }}</h2>
<div class="sea-creature-container">
<div class="genus-photo"></div>
<div class="genus-details">
<dl class="genus-details-list">
... lines 12 - 21
<dd>
<ul class="list-group">
{% for genusScientist in genus.genusScientists %}
<li class="list-group-item js-scientist-item">
... lines 26 - 40
</li>
{% endfor %}
</ul>
</dd>
</dl>
</div>
</div>
<div id="js-notes-wrapper"></div>
{% endblock %}
... lines 50 - 91

That'll also help in JavaScript.

Making the AJAX Call

Scroll back to the javascripts block. I'll paste a few lines of code here to get us started:

... lines 1 - 50
{% block javascripts %}
... lines 52 - 66
<script>
jQuery(document).ready(function() {
$('.js-remove-scientist-user').on('click', function(e) {
e.preventDefault();
var $el = $(this).closest('.js-scientist-item');
$(this).find('.fa-close')
.removeClass('fa-close')
.addClass('fa-spinner')
.addClass('fa-spin');
... lines 78 - 86
});
});
</script>
{% endblock %}

Ok, no big deal: the first line uses $(this), which is the link that was just clicked, and finds the .js-scientist-item li that is around it. We'll use that in a minute. The second chunk changes the fa-close icon into a loading spinner... ya know... because we deserve fancy things.

The real work - the AJAX call - is up to us. I'll use $.ajax(). Set the url key to $(this).data('url') to read the attribute we just set. And then, set method to DELETE:

... lines 1 - 50
{% block javascripts %}
... lines 52 - 66
<script>
jQuery(document).ready(function() {
$('.js-remove-scientist-user').on('click', function(e) {
e.preventDefault();
var $el = $(this).closest('.js-scientist-item');
$(this).find('.fa-close')
.removeClass('fa-close')
.addClass('fa-spinner')
.addClass('fa-spin');
$.ajax({
url: $(this).data('url'),
method: 'DELETE'
... lines 82 - 83
});
... lines 85 - 86
});
});
</script>
{% endblock %}

To add a little bit more fancy, add a .done(). After the AJAX call finishes, call $el.fadeOut() so that the item disappears in dramatic fashion:

... lines 1 - 50
{% block javascripts %}
... lines 52 - 66
<script>
jQuery(document).ready(function() {
$('.js-remove-scientist-user').on('click', function(e) {
... lines 70 - 78
$.ajax({
url: $(this).data('url'),
method: 'DELETE'
}).done(function() {
$el.fadeOut();
});
... lines 85 - 86
});
});
</script>
{% endblock %}

Testing time! Refresh.

Cute close icon, check! Click it! It faded away in dramatic fashion! Yes!

Checking the Delete Query

Check out the web debug toolbar's AJAX icon. Mixed in with AJAX call for notes is our DELETE call. Click the little sha, then go to the Doctrine tab. Ooh, look at this:

DELETE FROM genus_scientist WHERE genus_id = 11 AND user_id = 11

Gosh darn it that's nice. To prove it, refresh: the scientist is gone. ManyToMany? Yea, it's as simple as adding and removing objects from an array.

Well, ok, it will get a bit harder soon...

Leave a comment!

This course is built on Symfony 3, but most of the concepts apply just fine to newer versions of Symfony.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*", // v3.1.4
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.4
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "knplabs/knp-markdown-bundle": "^1.4", // 1.4.2
        "doctrine/doctrine-migrations-bundle": "^1.1", // 1.1.1
        "stof/doctrine-extensions-bundle": "^1.2" // v1.2.2
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.7
        "symfony/phpunit-bridge": "^3.0", // v3.1.3
        "nelmio/alice": "^2.1", // 2.1.4
        "doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
    }
}