If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeLet's do the easy thing first: when we submit the form successfully, these errors need to disappear!
We already have code for that, so copy it, and isolate it into its own new method called _removeFormErrors
:
... lines 1 - 2 | |
(function(window, $) { | |
... lines 4 - 24 | |
$.extend(window.RepLogApp.prototype, { | |
... lines 26 - 107 | |
_removeFormErrors: function() { | |
var $form = this.$wrapper.find(this._selectors.newRepForm); | |
$form.find('.js-field-error').remove(); | |
$form.find('.form-group').removeClass('has-error'); | |
}, | |
... lines 113 - 119 | |
}); | |
... lines 121 - 138 | |
})(window, jQuery); |
Call that from our map function:
... lines 1 - 2 | |
(function(window, $) { | |
... lines 4 - 24 | |
$.extend(window.RepLogApp.prototype, { | |
... lines 26 - 88 | |
_mapErrorsToForm: function(errorData) { | |
this._removeFormErrors(); | |
var $form = this.$wrapper.find(this._selectors.newRepForm); | |
... lines 92 - 105 | |
}, | |
... lines 107 - 119 | |
}); | |
... lines 121 - 138 | |
})(window, jQuery); |
The other thing we should do is empty, or reset the fields after submit. Let's create another function that does that and removes the form's errors. Call it _clearForm
. First call this._removeFormErrors()
:
... lines 1 - 2 | |
(function(window, $) { | |
... lines 4 - 24 | |
$.extend(window.RepLogApp.prototype, { | |
... lines 26 - 113 | |
_clearForm: function() { | |
this._removeFormErrors(); | |
... lines 116 - 118 | |
} | |
}); | |
... lines 121 - 138 | |
})(window, jQuery); |
To "reset" the form, get the DOM Element itself - there will be only one - by using [0]
and calling reset()
on it:
... lines 1 - 2 | |
(function(window, $) { | |
... lines 4 - 24 | |
$.extend(window.RepLogApp.prototype, { | |
... lines 26 - 113 | |
_clearForm: function() { | |
this._removeFormErrors(); | |
var $form = this.$wrapper.find(this._selectors.newRepForm); | |
$form[0].reset(); | |
} | |
}); | |
... lines 121 - 138 | |
})(window, jQuery); |
I love that this [0]
thing isn't a mystery anymore!
Call this from up in success: self._clearForm()
:
... lines 1 - 2 | |
(function(window, $) { | |
... lines 4 - 24 | |
$.extend(window.RepLogApp.prototype, { | |
... lines 26 - 65 | |
handleNewFormSubmit: function(e) { | |
... lines 67 - 74 | |
$.ajax({ | |
... lines 76 - 78 | |
success: function(data) { | |
self._clearForm(); | |
}, | |
... lines 82 - 85 | |
}); | |
}, | |
... lines 88 - 119 | |
}); | |
... lines 121 - 138 | |
})(window, jQuery); |
Ok, test this baby out! Submit it empty, then fill it out for real and submit. Boom!
Ok, back to the main task: on success, we need to add a new row to the table. We could do this the easy way: by manually parsing the JSON and building the table. But there's one big problem: I do not want to duplicate the row markup in Twig AND in JavaScript. Instead, we're going to use client-side templates.
Let's start off simple: at the bottom of our object, add a new function: _addRow
that has a repLog
argument. For now just log that: this will be the RepLog data that the AJAX call sends back:
... lines 1 - 2 | |
(function(window, $) { | |
... lines 4 - 24 | |
$.extend(window.RepLogApp.prototype, { | |
... lines 26 - 121 | |
_addRow: function(repLog) { | |
console.log(repLog); | |
} | |
}); | |
... lines 126 - 143 | |
})(window, jQuery); |
Call this from up in the success
callback: self._addRow(data)
:
... lines 1 - 2 | |
(function(window, $) { | |
... lines 4 - 24 | |
$.extend(window.RepLogApp.prototype, { | |
... lines 26 - 65 | |
handleNewFormSubmit: function(e) { | |
... lines 67 - 74 | |
$.ajax({ | |
... lines 76 - 78 | |
success: function(data) { | |
self._clearForm(); | |
self._addRow(data); | |
}, | |
... lines 83 - 86 | |
}); | |
}, | |
... lines 89 - 124 | |
}); | |
... lines 126 - 143 | |
})(window, jQuery); |
Let's make sure things are working so far: refresh and add a new element. Yes! The data has id
, itemLabel
and even a links
key with a URL for this RepLog. We are ready to template!
In a nutshell, a client-side, or JavaScript templating engine is like having Twig, but in JavaScript. There are a lot of different JavaScript templating libraries, but they all work the same: write a template - a mixture of HTML and dynamic code - and then render it, passing in variables that are used inside. Again, it's just like using Twig... but in JavaScript!
One simple templating engine comes from a library called Underscore.js. This is basically a bunch of nice, utility functions for arrays, strings and other things. It also happens to have a templating engine.
Google for Underscore CDN so we can be lazy and include it externally. Copy the minified version and then go back and open app/Resources/views/base.html.twig
. Add the new script tag at the bottom:
... lines 1 - 90 | |
{% block javascripts %} | |
... lines 92 - 93 | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> | |
{% endblock %} | |
... lines 96 - 99 |
Now, let's start templating!
"Houston: no signs of life"
Start the conversation!
// composer.json
{
"require": {
"php": "^7.2.0",
"symfony/symfony": "3.1.*", // v3.1.10
"twig/twig": "2.10.*", // v2.10.0
"doctrine/orm": "^2.5", // v2.7.1
"doctrine/doctrine-bundle": "^1.6", // 1.10.3
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.2
"symfony/swiftmailer-bundle": "^2.3", // v2.4.0
"symfony/monolog-bundle": "^2.8", // 2.12.0
"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
"friendsofsymfony/user-bundle": "~2.0@dev", // dev-master
"doctrine/doctrine-fixtures-bundle": "~2.3", // v2.4.1
"doctrine/doctrine-migrations-bundle": "^1.2", // v1.2.1
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"friendsofsymfony/jsrouting-bundle": "^1.6" // 1.6.0
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.1.1
"symfony/phpunit-bridge": "^3.0" // v3.1.6
}
}