Buy
Buy

Lift Stuff! The js- Prefix

Guys, get ready to pump up... on your JavaScript skills! No, no, I'm not talking about the basics. Look, I get it: you know how to write JavaScript, you're a ninja and a rock star all at once with jQuery. That's awesome! In fact, it's exactly where I want to start. Because in this tutorial, we're going to flex our muscles and start asking questions about how things - that we've used for years - actually work.

And this will make us more dangerous right away. But, but but! It's also going to lead us to our real goal: building a foundation so we can learn about ridiculously cool things in future tutorials, like module loaders and front-end frameworks like ReactJS. Yep, in a few short courses, we're going to take a traditional HTML website and transform it into a modern, hipster, JavaScript-driven front-end. So buckle up.

The Project: Pump Up!

As always, please, please, please, do the heavy-lifting and code along with me. By the way, in 30 seconds, I promise you'll understand why I'm making all these amazing weight-lifting puns. I know, you just can't... weight.

Anyways, download the course code from any page and unzip it to find a start/ directory. That will have the same code that you see here. Follow the details in the README.md file to get your project set up.

The last step will be to open a terminal, move into your project and do 50 pushups. I mean, run:

./bin/console server:run

to start the built-in PHP web server. Now, this is a Symfony project but we're not going to talk a lot about Symfony: we'll focus on JavaScript. Pull up the site by going to http://localhost:8000.

Welcome... to Lift Stuff: an application for programmers, like us, who spend all of their time on a computer. With Lift Stuff, they can stay in shape and record the things that they lift while working.

Let me show you: login as ron_furgandy, password pumpup. This is the only important page on the site. On the left, we have a history of the things that we've lifted, like our cat. We can lift many different things, like a fat cat, our laptop, or our coffee cup. Let's get in shape and lift our coffee cup 10 times. I lifted it! Our progress is saved, and we're even moving up the super-retro leaderboard on the right! I'm coming for you Meowly Cyrus!

But, from a JavaScript standpoint, this is all incredibly boring, I mean traditional! Our first job - in case I fall over my keyboard while eating a donut and mess up - is to add a delete icon to each row. When we click that, it should send an AJAX request to delete that from the database, remove the row entirely from the page, and update the total at the bottom.

Right now, this entire page is rendered on the server, and the template lives at app/Resources/views/lift/index.html.twig:

{% extends 'base.html.twig' %}
{% block body %}
<div class="row">
<div class="col-md-7">
<h2>
Lift History
<a href="#list-stuff-form" class="btn btn-md btn-success pull-right">
<span class="fa fa-plus"></span> Add
</a>
</h2>
<table class="table table-striped">
<thead>
<tr>
<th>What</th>
<th>How many times?</th>
<th>Weight</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
{% for repLog in repLogs %}
<tr>
<td>{{ repLog.itemLabel|trans }}</td>
<td>{{ repLog.reps }}</td>
<td>{{ repLog.totalWeightLifted }}</td>
<td>
&nbsp;
</td>
</tr>
{% else %}
<tr>
<td colspan="4">Get liftin'!</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td>&nbsp;</td>
<th>Total</th>
<th>{{ totalWeight }}</th>
<td>&nbsp;</td>
</tr>
</tfoot>
</table>
{{ include('lift/_form.html.twig') }}
</div>
<div class="col-md-5">
<div class="leaderboard">
<h2 class="text-center"><img class="dumbbell" src="{{ asset('assets/images/dumbbell.png') }}">Leaderboard</h2>
{{ include('lift/_leaderboard.html.twig') }}
</div>
</div>
</div>
{% endblock %}

Inside, we're looping over something I call a repLog to build the table:

... lines 1 - 2
{% block body %}
<div class="row">
<div class="col-md-7">
... lines 6 - 12
<table class="table table-striped">
... lines 14 - 22
{% for repLog in repLogs %}
<tr>
<td>{{ repLog.itemLabel|trans }}</td>
<td>{{ repLog.reps }}</td>
<td>{{ repLog.totalWeightLifted }}</td>
<td>
&nbsp;
</td>
</tr>
... lines 32 - 35
{% endfor %}
... lines 37 - 45
</table>
... lines 47 - 49
</div>
... lines 51 - 57
</div>
{% endblock %}

Each repLog represents one item we've lifted, and it's the only important table in the database. It has an id, the number of reps that we lifted and the total weight:

... lines 1 - 8
/**
* RepLog
*
* @ORM\Table(name="rep_log")
* @ORM\Entity(repositoryClass="AppBundle\Repository\RepLogRepository")
*/
class RepLog
{
... lines 17 - 27
/**
* @var integer
*
* @Serializer\Groups({"Default"})
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var integer
*
* @Serializer\Groups({"Default"})
* @ORM\Column(name="reps", type="integer")
* @Assert\NotBlank(message="How many times did you lift this?")
* @Assert\GreaterThan(value=0, message="You can certainly life more than just 0!")
*/
private $reps;
/**
* @var string
*
* @Serializer\Groups({"Default"})
* @ORM\Column(name="item", type="string", length=50)
* @Assert\NotBlank(message="What did you lift?")
*/
private $item;
/**
* @var float
*
* @Serializer\Groups({"Default"})
* @ORM\Column(name="totalWeightLifted", type="float")
*/
private $totalWeightLifted;
... lines 64 - 198
}

To add the delete link, inside the last <td> add a new anchor tag. Set the href to #, since we plan to let JavaScript do the work. And then, give it a class: js-delete-rep-log:

... lines 1 - 2
{% block body %}
<div class="row">
<div class="col-md-7">
... lines 6 - 12
<table class="table table-striped">
... lines 14 - 22
{% for repLog in repLogs %}
<tr>
... lines 25 - 27
<td>
<a href="#" class="js-delete-rep-log">
... line 30
</a>
</td>
</tr>
... lines 34 - 37
{% endfor %}
... lines 39 - 47
</table>
... lines 49 - 51
</div>
... lines 53 - 59
</div>
{% endblock %}
... lines 62 - 72

Inside, add our cute little delete icon:

... lines 1 - 2
{% block body %}
<div class="row">
<div class="col-md-7">
... lines 6 - 12
<table class="table table-striped">
... lines 14 - 22
{% for repLog in repLogs %}
<tr>
... lines 25 - 27
<td>
<a href="#" class="js-delete-rep-log">
<span class="fa fa-trash"></span>
</a>
</td>
</tr>
... lines 34 - 37
{% endfor %}
... lines 39 - 47
</table>
... lines 49 - 51
</div>
... lines 53 - 59
</div>
{% endblock %}
... lines 62 - 72

Adorable! Ok, first! Why did we add this js-delete-rep-log class? Well, there are only ever two reasons to add a class: to style that element, or because you want to find it in JavaScript.

Our goal is the second, and by prefixing the class with js-, it makes that crystal clear. This is a fairly popular standard: when you add a class for JavaScript, give it a js- prefix so that future you doesn't need to wonder which classes are for styling and which are for JavaScript. Future you will... thank you.

Copy that class and head to the bottom of the template. Add a block javascripts, endblock and call the parent() function:

... lines 1 - 62
{% block javascripts %}
{{ parent() }}
... lines 65 - 70
{% endblock %}

This is Symfony's way of adding JavaScript to a page. Inside, add a <script> tag and then, use jQuery to find all .js-delete-rep-log elements, and then .on('click'), call this function. For now, just console.log('todo delete!'):

... lines 1 - 62
{% block javascripts %}
{{ parent() }}
<script>
$('.js-delete-rep-log').on('click', function() {
console.log('todo delete!');
});
</script>
{% endblock %}

Resolving External JS in PHPStorm

But hmm, PhpStorm says that $ is an unresolved function or method. Come on! I do have jQuery on the page. Open the base layout file - base.html.twig - and scroll to the bottom:

<!DOCTYPE html>
<html lang="en">
... lines 3 - 19
<body>
... lines 21 - 90
{% block javascripts %}
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
{% endblock %}
</body>
</html>

Both jQuery and Bootstrap should be coming in from a CDN. Oh, but this note says that there is no locally stored library for the http link. Aha! Tell PhpStorm to download and learn all about the library by pressing Option+Enter on a Mac - or Alt+Enter on Linux or Windows - and choosing "Download Library". Do the same thing for Bootstrap.

Et voilà! The error is gone, and we'll start getting at least some auto-completion.

Using .on() versus .click()

Oh, and I want you to notice one other thing: we're using .on('click') instead of the .click() function. Why? Well, they both do the same thing. But, there are an infinite number of events you could listen to on any element: click, change, keyup, mouseover or even custom, invented events. By using .on(), we have one consistent way to add a listener to any event.

It's a small start, but already when we refresh, open the console, and click delete, it works! Now, let's follow the rabbit hole deeper.

Leave a comment!

  • 2019-03-05 Victor Bocharsky

    Hey Anisur!

    Write passwords explicitly is not a good idea :p Thank you for sharing your workflow and experience with others. Actually, we had the exact same steps in the README file inside /start and finish/ directories of the downloaded code. And also some useful tips too, don't miss it ;)

    Cheers!

  • 2019-03-03 Anisur Rahman

    Here is my installation process:
    Step 1. Download code

    Step 2. modify parameters.yml

    # This file is auto-generated during the composer install
    parameters:
    database_host: 127.0.0.1
    database_port: 33067
    database_name: symfony
    database_user: root
    database_password: null
    secret: ThisTokenIsNotSoSecretChangeIt

    Acquia Devdesktop database_port: 33067

    Step 3: $ composer install
    Loading composer repositories with package information
    Installing dependencies (including require-dev) from lock file
    Package operations: 41 installs, 0 updates, 0 removals
    - Installing doctrine/lexer (v1.0.1): Loading from cache
    ...
    [OK] All assets were successfully installed.

    Step 4:
    $ php bin/console doctrine:database:create
    Created database `symfony` for connection named default

    $ php bin/console doctrine:migrations:migrate

    Application Migrations


    WARNING! You are about to execute a database migration that could result in schema changes and data lost. Are you sure you wish to continue? (y/n)y
    Migrating up to 20170119105442 from 0

    ++ migrating 20161115100817

    -> CREATE TABLE rep_log (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, reps INT NOT NULL, item VARCHAR(50) NOT NULL, totalWeightLifted DOUBLE PRECISION NOT NULL, INDEX IDX_A460CE79A76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB
    -> CREATE TABLE tough_user (id INT AUTO_INCREMENT NOT NULL, username VARCHAR(180) NOT NULL, username_canonical VARCHAR(180) NOT NULL, email VARCHAR(180) NOT NULL, email_canonical VARCHAR(180) NOT NULL, enabled TINYINT(1) NOT NULL, salt VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, last_login DATETIME DEFAULT NULL, locked TINYINT(1) NOT NULL, expired TINYINT(1) NOT NULL, expires_at DATETIME DEFAULT NULL, confirmation_token VARCHAR(180) DEFAULT NULL, password_requested_at DATETIME DEFAULT NULL, roles LONGTEXT NOT NULL COMMENT '(DC2Type:array)', credentials_expired TINYINT(1) NOT NULL, credentials_expire_at DATETIME DEFAULT NULL, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_C760320692FC23A8 (username_canonical), UNIQUE INDEX UNIQ_C7603206A0D96FBF (email_canonical), UNIQUE INDEX UNIQ_C7603206C05FB297 (confirmation_token), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB
    -> ALTER TABLE rep_log ADD CONSTRAINT FK_A460CE79A76ED395 FOREIGN KEY (user_id) REFERENCES tough_user (id)

    ++ migrated (0.15s)

    ++ migrating 20170119105442

    -> ALTER TABLE tough_user DROP locked, DROP expired, DROP expires_at, DROP credentials_expired, DROP credentials_expire_at, CHANGE salt salt VARCHAR(255) DEFAULT NULL

    ++ migrated (0.03s)

    ------------------------

    ++ finished in 0.18s
    ++ 2 migrations executed
    ++ 4 sql queries

    $ php bin/console doctrine:fixtures:load
    Careful, database will be purged. Do you want to continue y/N ?y
    > purging database
    > loading AppBundle\DataFixtures\ORM\LoadReps


    $ php bin/console server:run


    [OK] Server running on http://127.0.0.1:8000


    // Quit the server with CONTROL-C.

    Step5: go to browser and paste http://127.0.0.1:8000
    with userName:
    Password

  • 2019-02-07 Diego Aguiar

    Ohh I get it. Yes, that feature is exclusive of PHPStorm, but you still have to use a CDN or download the assets in order to use them on your app.

  • 2019-02-06 Peter

    I don't have PHP Storm. I'm using Visual Studio Code as my editor. That means I don't have access to that Option+Enter function to download the CDN libraries. But you say that's only for autocomplete? I'll give it another try.

  • 2019-02-06 Diego Aguiar

    Hey Peter. What you mean with "Am I at great handicap using Visual Studio Code? Is there a workaround"?

    If your PhpStorm is not downloading the assets maybe you should upgrade it first. Anyway, if you can't download the assets it won't impact you at anything but autocompletion

    Cheers!

  • 2019-02-06 Diego Aguiar

    Awesome! And yeah, I ran into that problem as well, took some time to find a solution.
    Cheers!

  • 2019-02-06 Peter

    I'm having an issue not being able to perform the PHPStorm command to download the CDN libraries. Am I at great handicap using Visual Studio Code? Is there a workaround? I thought I'd just download and add to a library folder but couldn't find it.
    Thanks

    To quote:

    Both jQuery and Bootstrap should be coming in from a CDN. Oh, but this note says that there is no locally stored library for the http link. Aha! Tell PhpStorm to download and learn all about the library by pressing Option+Enter on a Mac - or Alt+Enter on Linux or Windows - and choosing "Download Library". Do the same thing for Bootstrap.
  • 2019-02-06 Peter

    That did the trick. I ran this code (tweaked) in the Workbench query panel then clicked the lightning bolt:

    ALTER USER 'mysqlUsername'@'localhost' IDENTIFIED WITH mysql_native_password BY 'mysqlUsernamePassword';

    Then ran the startup code in the terminal:

    php bin/console doctrine:database:create
    php bin/console doctrine:migrations:migrate
    php bin/console doctrine:fixtures:load

    And I'm now able to not only pull up the app's page but also log in as ron_furgundy. Woohoo!

    Thanks so much for your help. These version changes can drive you crazy.

  • 2019-02-05 Diego Aguiar

    Ohh you are on MySql 8, in that version the password encryption changed. Take a look to this post: https://stackoverflow.com/q...

    You can just tweak this query and run it
    ALTER USER 'mysqlUsername'@'localhost' IDENTIFIED WITH mysql_native_password BY 'mysqlUsernamePassword'

  • 2019-02-05 Peter

    Diego, thanks for that. I had been using Symfony 4 but I changed to Symfony 3. I also reinstalled Mysql v8, as I believe it had some problems. Msql workbench now shows some functioning databases. I tried once again to set up this tutorial following the Readme file, but ran into some issues when I ran 'php bin/console doctrine:database:create'. I got 4 red error messages, all of them mentioning "The server requested authentication method unknown to the client."

    I then went back to the Symfony docs on setup, https://symfony.com/doc/3.4..., and was able to follow the steps to create a new Symfony install:

    composer create-project symfony/framework-standard-edition symfony-composer-test "3.4.*"

    I was prompted for database host, port, name, etc. It seemed to work. I then started it up using:

    php bin/console server:run

    Got the confirmation:

    [OK] Server listening on http://127.0.0.1:8000

    Also, I made sure to select port 3306. I did give it a password, tho.

    Doesn't this mean I now have what it takes to run this tutorial? If the tutorial install keeps failing, can I just copy the lesson files into my new install, and proceed with the lesson? Newbie questions, as I've not worked in this environment before.

    One thing that puzzles is where the new db ended up. I named it 'symfony2' but do not see it in the Mysql Workbench interface.

    Thanks for whatever help you can give me!

  • 2019-01-29 Victor Bocharsky

    Hey Hanene,

    I'm glad you found what you were looking for! Yes, all the code behind our tutorials os public and available on our GitHub organizations:
    https://github.com/symfonyc...
    https://github.com/knpunive...

    Though, since we somethings we use the same repository for a few tutorials, it would be good to know that the latest commit will contain all the changes from all previous tutorials that are based on the repository.

    Cheers!

  • 2019-01-29 hanene

    I have found the code when viewing on GitHub https://github.com/knpunive...

  • 2019-01-28 Diego Aguiar

    I left you a couple of questions in the other comment

  • 2019-01-28 Diego Aguiar

    Hey Peter

    Which version of Symfony are you using? If you are on Symfony4, then the parameters.yml file doesn't exist anymore

    Double check that your DB is actually listening to 3306 port, and the user "root" exists with no password

    Cheers!

  • 2019-01-28 Victor Bocharsky

    Hey Hanene,

    Do you mean you cannot download the code? Hm, I just double checked and it works for me. Could you try again?

    Cheers!

  • 2019-01-26 Peter

    Not sure how to send you the source files. I'm basically just starting with the zipped course files, code-javascript.zip. There's only one config file to tweak that I know of, parameters.yml. It derives from the parameters.yml.dist, which has a ~ for bothe database_port and database_password:

    # This file is a "template" of what your parameters.yml file should look like
    # Set parameters here that may be different on each deployment target of the app, e.g. development, staging, production.
    # http://symfony.com/doc/curr...
    parameters:
    database_host: 127.0.0.1
    database_port: ~
    database_name: symfony
    database_user: root
    database_password: ~
    # You should uncomment this if you want use pdo_sqlite
    # database_path: "%kernel.root_dir%/data.db3"

    I ran composer install and was prompted for these settings. I accepted defaults for all values except password and port. It resulted in this parameters.yml file auto generated:

    # This file is auto-generated during the composer install
    parameters:
    database_host: 127.0.0.1
    database_port: 3306
    database_name: symfony
    database_user: root
    database_password: root
    secret: ThisTokenIsNotSoSecretChangeIt

    The basic error message when I run

    php bin/console doctrine:database:create

    looks like this:

    [Doctrine\DBAL\Exception\ConnectionException]
    An exception occured in driver: SQLSTATE[HY000] [2002] Connection refused

    Searching that, I found a Stackexchange link:

    https://stackoverflow.com/q...

    Here's the gist of that message:

    The connection is refused so it is time for a systematic debug process:

    Identify the host, user, and password being used to connect. These will be in wherever Symfony stores such things.

    If those details are present and look correct then use them to log into your database directly (via the command line) to verify that they actually are correct.

    Check the hostname actually resolves to where the database is hosted. For example, if the database is on the same machine as PHP and the hostname used is db-production then check on your Operating System's hosts file for this entry and make sure it resolves to 127.0.0.1. Typically I would expect the host is set to localhost, in which case you can still check the hosts file, but it will probably be in there.

    Once you have established that the host, user, and password are correct the only thing left is Symfony not behaving as expected. In which case I am all out of ideas.

    ---

    So I obviously need to dig into setting up a db in Symfony. Specifically: "Identify the host, user, and password being used to connect. These will be in wherever Symfony stores such things." But I can't seem to find the core Symfony install. I also assume that I need to know more about my local install of mysql. I in fact recently installed Mysql Workbench and Mysql Community Server for a tutorial on Mamp. I do have Mysql running with an active database but it doesn't seem to connect with my attempt to install the Symfonycasts Javascript course.

    So far I've only completed one course in Symfony 4 so I'm almost a complete newbie. Where do I go for help? Any advice is appreciated!

  • 2019-01-26 hanene

    hi ,I can't attend the course code .. Could you please send me the whole files as soon as possible

  • 2019-01-26 hanen

    hi ,I can't attend the course code .. Could you please send me the whole files as soon as possible.

  • 2019-01-25 Peter

    Really eager to start this tute. However I can't seem to set up the db. Any help would be greatly appreciate!!

    Here is my parameters.yml file. I used 3306 as the database port, since I believe it's the default for mysql:

    # This file is auto-generated during the composer install
    parameters:
    database_host: 127.0.0.1
    database_port: 3306
    database_name: symfony
    database_user: root
    database_password: root
    secret: ThisTokenIsNotSoSecretChangeIt

    This is what I get in the terminal when trying to create the db:

    P-Ts-MBP-9:start owner$ sudo php bin/console doctrine:database:create

    [Doctrine\DBAL\Exception\ConnectionException]
    An exception occured in driver: SQLSTATE[HY000] [2002] Connection refused

    [Doctrine\DBAL\Driver\PDOException]
    SQLSTATE[HY000] [2002] Connection refused

    [PDOException]
    SQLSTATE[HY000] [2002] Connection refused

  • 2018-08-30 weaverryan

    Hey Tomasz Gąsior!

    Yep, you're totally right - that was lazy on my part :). Thanks for the comment - I'll pay closer attention to this in the future!

    Cheers!

  • 2018-08-30 Victor Bocharsky

    Hey Tomasz,

    Ah, now I see... Yeah, makes sense, and it good to know! Thanks for pointing us about it.

    Cheers!

  • 2018-08-29 Tomasz Gąsior

    Thank you for your response.

    Sorry! I was talking about "delete" button on each row. But I given you wrong time stamp. It should be around 4:30.

    Hyperlinks have to be used to indicate URL change. Buttons (<button type="button">) should be used if URL is not changed and action is fired on JavaScript side. This is important for a11y. Please look at this articles:
    * https://blogs.ancestry.com/...
    * https://marcysutton.com/lin...

  • 2018-08-29 Victor Bocharsky

    Hey Tomasz,

    Are you talking about "I lifted it" button? That's exactly what we press at 3:00 in the video, and it is a button tag. But anyway, using "a" tag with href="#" is totally OK as for me, because it has a valid HTML syntax. Why don't you like it?

    Cheers!

  • 2018-08-28 Tomasz Gąsior

    3:00 — from HTML semantic perspective you should use <button type="button"> instead of (a href="#"). (a) should not be used with senseless href="" value.
    (For some reason Discuss does not escape "A" html tag in comments.)

  • 2018-06-01 Victor Bocharsky

    Hey Leora,

    Thanks for sharing this with others! Yes, new version of FOSUserBundle requires this configuration to be able to run the project, so if you download our code and run "composer update" - you need to specify those keys.

    Cheers!

  • 2018-05-30 Leora Wenger

    I added this to config.yml and it was happy.


    fos_user:
    from_email:
    address: "info@somewhere.com"
    sender_name: "No Reply"


  • 2018-05-30 Leora Wenger

    Hi, I am going through the instructions in the ReadMe.
    I got this one:
    [Symfony\Component\Config\Definition\Exception\InvalidConfigurationException]
    The child node "from_email" at path "fos_user" must be configured.

  • 2018-05-24 Victor Bocharsky

    Hey Xi,

    Thanks for sharing it! Yes, probably some important BC break was provided by PHP 7.2, so upgrading deps is always a good idea if you have errors in vendors.

    Cheers!

  • 2018-05-23 Xi Wang

    Same happened while doing a revision - was fine before PHP 7.2

    I fixed it by doing a 'composer update'. Hope it helps.

  • 2018-05-23 Adam

    Hi

    I'm getting the same error when I click 'I lifted it'.
    I'm using PHP 7.2

    Adam

  • 2018-04-30 weaverryan

    Hey sandeep sangole!

    Hmmm. Can you post your RepLogApp.js? Exactly how far through the tutorial are you? I'm asking because we don't create the RepLogApp.js file until chapter 12 of this tutorial (https://knpuniversity.com/s..., so I need to know exactly where you are :).

    But, I also think that I recognize the error. Near the end of the tutorial (https://knpuniversity.com/s..., we update our code to make an AJAX request to an API and we *expect* our API endpoint to return JSON. We then use JSON.parse() to parse that JSON, so we can handle it.

    I believe the error is coming from there. Specifically, for some reason, your API endpoint is NOT returning JSON - it's probably returning HTML, maybe an error page. And so, RepLogApp.js throws an error when it tries to parse this as JSON. The "Unrecognized token '<'" is because it is seeing an HTML tag, instead of JSON.

    So, check your AJAX request and see why it's not returning JSON :).

    Cheers!

  • 2018-04-30 Victor Bocharsky

    Hey Sandeep,

    I already answered this question replying your email, so I just duplicate the answer here:

    Thanks for reporting it! Hm, probably you just missed some steps in the README files of the code downloads? If all of the precondition steps were executed, could you tell me a bit more how did you get this error? I really interested in steps to reproduce it. Did you unzip the code, change the current directory to "start/", run all the necessary steps from both README files: in rood dir and in start/ dir, and run the project? On what page did you get this error? What do you do exactly, do you press any buttons? And btw, what is your PHP version?

    I'm trying to understand whether it's user specific error or we really have a bug somewhere in our code.

    Cheers!

  • 2018-04-30 Victor Bocharsky

    Hey Sandeep,

    You can easily edit your comments, so no need to write a several comments if you forgot some details in the previous message ;) Also, we're tracking each Disqus comment, so do not need to duplicate the question in direct message. But yeah, Disqus comments is the best way to get help from us, and it's also may be useful for other people who will see comments, they may find already answered questions. Unfortunately, we do not able to answer your questions immediately, so we may reply back to you with some delay, please, keep in mind it. Thanks for understanding.

    Cheers!

  • 2018-04-29 sandeep sangole

    What is the best way to get help on below issues ??

  • 2018-04-29 sandeep sangole

    Below error is on finish project. Getting error on start project too :(

    Warning: count(): Parameter must be an array or an object that implements Countable

    500 Internal Server Error - ContextErrorException

    Stack Trace
    in vendor/symfony/symfony/src/Symfony/Component/Form/Form.php at line 716 -
    return FormUtil::isEmpty($this->modelData) ||
    // arrays, countables
    0 === count($this->modelData) ||
    // traversables that are not countable
    ($this->modelData instanceof \Traversable && 0 === iterator_count($this->modelData));
    }

  • 2018-04-29 sandeep sangole

    Hi there , I have just started course , downloaded source code and setup the application. While adding to lift history I am getting below error ,

    [Warning] jQuery.Deferred exception: JSON Parse error: Unrecognized token '<' (2) (jquery-3.1.1.min.js, line 2)

    parse

    (anonymous function) — RepLogApp.js:126

    j — jquery-3.1.1.min.js:1349

    (anonymous function) — jquery-3.1.1.min.js:1356

    undefined

  • 2018-04-10 Diego Aguiar

    Hey Prout

    I'm sorry that you are feeling that way. It has been never our intention to teach any bad practices, but when we do (because we are not aware of, or maybe the technology just evolved) we like to be told so. Anyways, this tutorial is not about JQuery, we used JQuery because is a handy library for doing a lot of common stuff, but, you can use any library you want, or even pure JS if you like.

    If you have any question or feedback, don't hesitate to contact us. Cheers!

  • 2018-04-08 Prout

    I'm discouraged that it's showing bad practices. jQuery IS a bad practice. Why the heck should I import 10k rows of stuffed code to do something I can do in 10 rows ?

  • 2017-07-20 Diego Aguiar

    Hey julien moulis!

    There are a few things that changes when moving from Dev to Prod, like cache, you have to clear it after making changes to your files, another one is the DB, you have a separated DataBase for Prod, so you will have to update the schema too.

    Give it a try and let us know if you have more problems :)

    Cheers!

  • 2017-07-20 julien moulis

    Hi everyone.
    I followed this course, and applied it to my app. It works pretty well on dev environnement, but as soon as I go on prod, onsubmit any forms, instead of returning errors to be displayed into my form, I get a dirty 500 explosion and no datas to be displayed... Any ideas?
    Thanks

  • 2017-04-03 Diego Aguiar

    Hey Pawel!

    That means you still need to install and activate doctrine migrations bundle, it doesn't come by default
    just run:


    composer require doctrine/doctrine-migrations-bundle

    and then open up your AppKernel.php and register it:


    $bundles = array(
    //...
    new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
    );

    You can read more about it here:
    http://symfony.com/doc/curr...

    Have a nice day!

  • 2017-04-03 Pawel End

    I have error when I run command "php bin/console doctrine:migrations:migrate"

    error: [Symfony\Component\Console\Exception\CommandNotFoundException]
    There are no commands defined in the "doctrine:migrations" namespace.
    Did you mean one of these?
    doctrine:query
    doctrine:schema
    doctrine:cache
    doctrine:generate
    doctrine:mapping
    doctrine:database
    doctrine

  • 2017-03-29 Victor Bocharsky

    Yeah, agree, file uploading is tough, but file uploading with JS is more tough ;)

    Cheers!

  • 2017-03-28 julien moulis

    Thanks Ryan for the quick answer.
    I'll go diving in the ocean of api rest... It will help, I guess to understand the course as well.

  • 2017-03-28 julien moulis

    Thanks Victor. For the moment I'll continue using a normal php upload. This plugin is great but tough to get it work for me, now.

  • 2017-03-27 Victor Bocharsky

    Hey Julien,

    Yeah, I had the same problem and I solved it with a third-party JS library which helps uploading files. I used jQuery-File-Upload, here's a demo how it works: https://blueimp.github.io/j... . Sorry, I didn't dive into it and don't know how exactly it works, but I know that this library do everything you need to upload files via AJAX. I hope it helps you.

    Cheers!

  • 2017-03-26 weaverryan

    Hey julien moulis!

    It's possible/likely that with this FormData, the data is sent as normal application/x-www-form-urlencoded format instead of as JSON. What that means is that you probably won't fetch and decode the request body as JSON. Instead, you'll treat it more like a traditional form upload:


    $filename = $request->request->get('ifileName');
    $uploadedFile = $request->files->get('fileTemporary');

    I hope that helps :)

  • 2017-03-25 julien moulis

    Actually I was trying formData, but it seems to break with the actual code of the course. "Invalid Jason", which I guess is normal. I'll give it a try.

  • 2017-03-25 weaverryan

    Ah, I think I know the problem! Uploading files with AJAX... well, it doesn't work :). Well, at least not traditionally - AJAX didn't originally ship with the ability to upload files. I think this may have changed (http://blog.teamtreehouse.c..., but I believe that most people still use some library or jQuery plugin to help with AJAX file uploads (it actually has *always* been possible, but required some hacks that these libraries can help you with).

    So, I would recommend trying out the FormData() object that the Treehouse blog talks about (I've actually never tried this myself) or use some sort of a plugin - e.g. google "jQuery AJAX file upload". You'll need to do a bit more work, but I hope this will at least end your frustration! It's not something you're doing wrong - AJAX itself is causing the problems!

    Cheers!

  • 2017-03-25 julien moulis

    This is making me crazy. Everything is working so well. It is just the input file(named fileTemporary beccause not persisted) that is not sent in the ajax call.
    {links: {_self: "/document/docs/106"}, id: 106, fileTemporary: null, fileName: "Test file"}
    Is there a specific action for the input file to do on an ajax call?

  • 2017-03-24 julien moulis

    Hi Victor,
    The Ajax request is sent, the entity is persisted. But the file upload, move and all the work that is done by vichuploadBundle doesn't work. On my form I have a input file and a textfield. When post the form and I check the Ajax request, and then the form (symphony debug toolbar), the input file is empty, so I guess that's probably why vich doctrine listener doesn't work. If you code or anything else tell me
    And everything works fine without using Ajax.

  • 2017-03-24 Victor Bocharsky

    Hey Julien,

    Ah, it's difficult to understand the problem. Could you debug it a bit more? Was the AJAX request sent? Were any errors occurred? You can use Google Chrome dev toolbar (there, in Console tab, you can see any JS errors that were occurred) and Symfony debug toolbar in dev environment, and also look for more information in your logs in "var/logs/" directory.

    Cheers!

  • 2017-03-24 julien moulis

    Hey everyone.
    I'm trying to apply the tutorial to my app. But I encounter a problem with the use of ajax and upload file. I'm using VichUploader. Haphazardly, have you ever encountered the pb? The file doesn't upload.

  • 2017-02-22 weaverryan

    Thanks Kieran Mathieson I always appreciate your feedback :). And I agree with both points - would probably be even better if we had a working, non-AJAX delete link first (to establish its purpose), then added the "fancy". And I don't often do the "So far, we've", but since it's easy to keep this to one sentence, I think it would add context without dragging things out.

    In other words, cheers! Will keep these things in mind for future tutorials. And nice to hear from you!

  • 2017-02-20 Kieran Mathieson

    Good stuff, Ryan. As usual. Good learning design, good implementation.

    Great positioning - people who use jQuery already, but need to adapt to the New Order.

    Perhaps show the delete button in action before coding it. Give the steps we'll be coding, e.g., (1) add an icon for the button, then (2)... Then refer back to the list at the start of each lesson. "So far, we've... Now, we'll..."

    Good operational hints, like starting class names with js-.

  • 2017-01-19 weaverryan

    Ha, you live dangerously :p. Actually, fortunately, most projects have pretty-well-locked down version constraints in composer.json, so not THAT dangerous... as long as you don't do this on production ;).

    Thanks again!

  • 2017-01-19 Raymond A

    Thanks !
    I always do a composer update when receiving a symfony project.

  • 2017-01-19 weaverryan

    Hey Raymond!

    And thanks for letting me know about a potential bug! So, the code download DOES work... but I wonder if you somehow upgraded to the latest version of FOSUserBundle? In our version, the salt was automatically set in the base User class. But, regardless, you made me realize that we should probably just upgrade the project to the latest FOSUserBundle to avoid confusing, which I'm doing right now. Then, all should be good (it includes a new migration to make "salt" nullable, because salt is now nullable in the latest FOSUserBundle).

    Cheers!

  • 2017-01-19 Raymond A

    Hi,
    Thanks for the tuts!
    However , the download code is missing the salt value in the fixtures and since the column is defined as NOT NULL.
    This generating an error when trying to load the fixtures as defined in the README.md.