This tutorial has a new version, check it out!

ReactJS talks to your API

Remove the link. In base.html.twig, we already have a few JavaScript files that are included on every page. But now, I want to include some JavaScript on just this page - I don't need this stuff everywhere.

Page-Specific JavaScript (or CSS)

Remember from earlier that those script tags live in a javascripts block. Hey, that's perfect! In the child template, we can override that block: {% block javascripts %} then {% endblock %}:

38 lines app/Resources/views/genus/show.html.twig
... lines 1 - 23
{% block javascripts %}
... lines 25 - 36
{% endblock %}

Now, whatever JS we put here will end up at the bottom of the layout. Perfect, right?

No, not perfect! When you override blocks, you override them completely. With this code, it will completely replace the other scripts in the base template. I don't want that! I really want to append content to this block.

The secret awesome solution to this is the parent() function:

38 lines app/Resources/views/genus/show.html.twig
... lines 1 - 23
{% block javascripts %}
{{ parent() }}
... lines 26 - 36
{% endblock %}

This prints all of the content from the parent block, and then we can put our cool stuff below that.

Including the ReactJS Code

Here's the goal: add some JavaScript that will make an AJAX request to the notes API endpoint and use that to render them with the same markup we had before. We'll use ReactJS to do this. It's powerful... and super fun, but if it's new to you, don't worry. We're not going to learn it now, just preview it to see how to get our API working with a JavaScript frontend.

First, include three external script tags for React itself. Next, I'm going to include one more script tag that points to a file in our project: notes.react.js:

38 lines app/Resources/views/genus/show.html.twig
... lines 1 - 23
{% block javascripts %}
{{ parent() }}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
<script type="text/babel" src="{{ asset('js/notes.react.js') }}"></script>
... lines 31 - 36
{% endblock %}

Let's check that file out! Remember, it's in web/js/notes.react.js:

69 lines web/js/notes.react.js
var NoteSection = React.createClass({
getInitialState: function() {
return {
notes: []
}
},
componentDidMount: function() {
this.loadNotesFromServer();
setInterval(this.loadNotesFromServer, 2000);
},
loadNotesFromServer: function() {
$.ajax({
url: '/genus/octopus/notes',
success: function (data) {
this.setState({notes: data.notes});
}.bind(this)
});
},
render: function() {
return (
<div>
<div className="notes-container">
<h2 className="notes-header">Notes</h2>
<div><i className="fa fa-plus plus-btn"></i></div>
</div>
<NoteList notes={this.state.notes} />
</div>
);
}
});
var NoteList = React.createClass({
render: function() {
var noteNodes = this.props.notes.map(function(note) {
return (
<NoteBox username={note.username} avatarUri={note.avatarUri} date={note.date} key={note.id}>{note.note}</NoteBox>
);
});
return (
<section id="cd-timeline">
{noteNodes}
</section>
);
}
});
var NoteBox = React.createClass({
render: function() {
return (
<div className="cd-timeline-block">
<div className="cd-timeline-img">
<img src={this.props.avatarUri} className="img-circle" alt="Leanna!" />
</div>
<div className="cd-timeline-content">
<h2><a href="#">{this.props.username}</a></h2>
<p>{this.props.children}</p>
<span className="cd-date">{this.props.date}</span>
</div>
</div>
);
}
});
window.NoteSection = NoteSection;

The ReactJS App

This is a small ReactJS app that uses our API to build all of the same markup that we had on the page before, but dynamically. It uses jQuery to make the AJAX call:

69 lines web/js/notes.react.js
var NoteSection = React.createClass({
... lines 2 - 12
loadNotesFromServer: function() {
$.ajax({
url: '/genus/octopus/notes',
success: function (data) {
this.setState({notes: data.notes});
}.bind(this)
});
},
... lines 21 - 32
});
... lines 34 - 69

But I have a hardcoded URL right now - /genus/octopus/notes. Obviously, that's a problem, and lame. But ignore it for a second.

Back in the template, we need to start up the ReactJS app. Add a script tag with type="text/babel" - that's a React thing. To boot the app, add ReactDOM.render:

38 lines app/Resources/views/genus/show.html.twig
... lines 1 - 23
{% block javascripts %}
... lines 25 - 29
<script type="text/babel" src="{{ asset('js/notes.react.js') }}"></script>
<script type="text/babel">
ReactDOM.render(
... lines 33 - 34
);
</script>
{% endblock %}

PhpStorm is not going to like how this looks, but ignore it. Render the NoteSection into document.getElementById('js-notes-wrapper'):

38 lines app/Resources/views/genus/show.html.twig
... lines 1 - 31
ReactDOM.render(
<NoteSection />,
document.getElementById('js-notes-wrapper')
);
... lines 36 - 38

Back in the HTML area, clear things out and add an empty div with this id:

38 lines app/Resources/views/genus/show.html.twig
... lines 1 - 4
{% block body %}
... lines 6 - 20
<div id="js-notes-wrapper"></div>
{% endblock %}
... lines 23 - 38

Everything will be rendered here.

Ya know what? I think we should try it. Refresh. It's alive! It happened quickly, but this is loading dynamically. In fact, I added some simple magic so that it checks for new comments every two seconds. Let's see if it'll update without refreshing.

In the controller, remove one of the notes - take out AquaWeaver in the middle. Back to the browser! Boom! It's gone. Now put it back. There it is! So, really cool stuff.

Generating the URL for JavaScript

But... we still have that hardcoded URL. That's still lame, and a problem. How you fix this will depend on if you're using AngularJS, ReactJS or something else. But the idea is the same: we need to pass the dynamic value into JavaScript. Change the URL to this.props.url:

69 lines web/js/notes.react.js
var NoteSection = React.createClass({
... lines 2 - 12
loadNotesFromServer: function() {
$.ajax({
url: this.props.url,
... lines 16 - 18
});
},
... lines 21 - 32
});
... lines 34 - 69

This means that we will pass a url property to NoteSection. Since we create that in the Twig template, we'll pass it in there.

First, we need to get the URL to the API endpoint. Add var notesUrl = ''. Inside, generate the URL with twig using path(). Pass it genus_show_notes and the genusName set to name:

40 lines app/Resources/views/genus/show.html.twig
... lines 1 - 23
{% block javascripts %}
... lines 25 - 30
<script type="text/babel">
var notesUrl = '{{ path('genus_show_notes', {'genusName': name}) }}';
... lines 33 - 37
</script>
{% endblock %}

Yes, this is Twig inside of JavaScript. And yes, I know it can feel a little crazy.

Finally, pass this into React as a prop using url={notesUrl}:

40 lines app/Resources/views/genus/show.html.twig
... lines 1 - 33
ReactDOM.render(
<NoteSection url={notesUrl} />,
document.getElementById('js-notes-wrapper')
);
... lines 38 - 40

Try that out. It still works very nicely.

Go Deeper!

There is also an open-source bundle called FOSJsRoutingBundle that allows you to generate URLs purely from JavaScript. It's pretty awesome.

Congrats on making it this far: it means you're serious! We've just started, but we've already created a rich HTML page and an API endpoint to fuel some sweet JavaScript. And we're just starting to scratch the surface of Symfony.

What about talking to a database, using forms, setting up security or handling API input and validation? How and why should you register your own services? And what are event listeners? The answers to these will make you truly dangerous not just in Symfony, but as a programmer in general.

See you on the next challenge.

Leave a comment!

  • 2017-12-08 Victor Bocharsky

    Hey Cesar,

    Hm, actually not much info about session as well. But you can take a look at these screencasts where we're talking about session and use some small examples, for example here: https://knpuniversity.com/s... and also see full ShoppingCart class: https://knpuniversity.com/s... - you can expand this code block or download course code and find this file in finish/ directory. This class has a nice example how to work with session, but we do not explain this file a lot in this tutorial, just show how to use it.

    Also, here's a few links to Symfony docs:
    https://symfony.com/doc/cur...
    https://symfony.com/doc/cur...

    Where you can see some related links. Good news is that Symfony docs has much more information about session than about cookie.

    Cheers!

  • 2017-12-07 Cesar

    Thanks for answering Victor. Unfortunately, I am beginner and I am learning a lot with your tutorials. Do you have any tutorial about sessions with Symfony 3? Please, let me know.

  • 2017-12-07 Victor Bocharsky

    Hey Cesar,

    Unfortunately, we do not have this one yet. But this topic is too little for a separate tutorial, but probably would be cool to cover this topic in another tutorial. However, we don't have any plans to do so in the nearest future, but we already have this topic in our ideas pool.

    But I can say this topic is not pretty complex. Actually, working with cookies very similar to working with sessions, so if you worked with sessions before - that's winning! You probably know about Symfony's famous Request object, which is a wrapper around such global vars as $_GET, $_POST, $_SESSION, and... $_COOKIE! So you can easily read/write cookies with it. Also, take a look at an example in Symfony docs: https://symfony.com/doc/cur... . The main problem, i.e. a subtle nuance is that cookies allow to store you a very little information, IIRC it's just 4kB, so you can't store much information in cookies. And instead of storing on the server side like sessions, cookies are stored on the client side, i.e. in a browser, but like sessions, cookies may have time to live.

    I hope this helps you a bit. If you have other questions - feel free to ask ;)

    Cheers!

  • 2017-12-06 Cesar

    Hello. Do you have any tutorial where you explain how to create and manage a cookie using Symphony 3? I will be more than happy to buy it. I hope you can help me.

  • 2017-10-27 Diego Aguiar

    Please do it! :)

  • 2017-10-27 AbelardoLG

    With my last comment I referred to your 'finish' version, not mine.
    I am investigating why my app doesn't work.
    Whenever I fix it, I will post here. :)

    Regards.

  • 2017-10-26 Diego Aguiar

    That's great! we moved one step further :)

    How did it go? could you fix it?

  • 2017-10-25 AbelardoLG

    It worked! I forgot to run "composer install" (Y)

    The notes were loaded too.

    I am still investigating why the notes are not loaded into my app.

    Cheers!

  • 2017-10-25 AbelardoLG

    By using Firefox (FF), it does happen the same: that .js file doesn't load. :S

  • 2017-10-25 Diego Aguiar

    Hey AbelardoLG

    Symfony couldnt find your autoloader file, look like you forgot to run `composer install`. Oh, also, there is a README file at the root of the project with setup instructions, you may find them useful

    Cheers!

  • 2017-10-25 AbelardoLG

    No, I haven't written this line in a wrong file.
    I think it's the cache problem.
    I will check it out with FF.

  • 2017-10-25 AbelardoLG

    Hi again,
    I have just uploaded a screenshot when I run the 'finish' version of your app.
    Please, check it out and let me know why these errors appear when I executed.
    Best regards.
    https://imgur.com/a/eZG6f

  • 2017-10-25 Victor Bocharsky

    That's great! It means you have this file and you can access it. So the problem is that you do not require it in HTML code, most probably it's the cache problem, you just need to clear the cache... or you wrote this line in a wrong file :)

  • 2017-10-25 AbelardoLG

    Yes, I have seen it to the end but at that point I am stuck due to this error.

  • 2017-10-25 AbelardoLG

    Its content.

  • 2017-10-25 AbelardoLG

    Yes, I see its content.

  • 2017-10-25 AbelardoLG

    Thanks :)

  • 2017-10-24 Diego Aguiar

    Hey AbelardoLG
    You only have to hit (inside web folder) `app.php` instead of `app_dev.php` file. Those files are you front controller, so it depends on which web server are you running, but basically you only have to switch your project public root path

    Cheers!

  • 2017-10-24 AbelardoLG

    At that point because I can't see the notes.

  • 2017-10-24 AbelardoLG

    It seems like that file is not detected by the browsers Opera nor Chrome.

  • 2017-10-24 AbelardoLG

    Definitively, that file doesn't appear in the list under network tab.

  • 2017-10-24 AbelardoLG

    No 404 error was showed while I had opened Chrome dev tools->Network tab

  • 2017-10-24 AbelardoLG

    The content of that file.

  • 2017-10-24 AbelardoLG

    Obviously, this file doesn't exist in view source code page. A new picture was uploaded to be verified by you.
    I executed that line but the problem persists.
    I deleted Opera cache and by using (cmd + R) and (cmd + alt + R) but none happens.
    How can I change between dev-prod environments with Symfony?

  • 2017-10-24 AbelardoLG

    Yes, i saw the video to the end. But in that minute, 2:30, you can show that notes but I can't do it.
    I am still investigating why I don't see the notes. Curious, I have the same code than you. ¿?

  • 2017-10-24 Victor Bocharsky

    Hey AbelardoLG ,

    Hm, that's interesting! So I see this file exists and you can get it by requesting http://localhost:8000/js/notes.react.js . But... I don't see it's loaded in Network tab, which means you don't have it in HTML code - probably it's due to cache! I bet if you press "Cmd + Option + U" (or right click -> View Page Source) you won't see the line:

    <script type="text/babel" src="{{ asset('js/notes.react.js') }}"></script>

    Could you double check it doesn't exist in page source code to be sure? So it means, you just need to clear the cache, which make sense if you load Symfony in production environment - you should always clear the cache manually in prod after any change in templates or in configuration. Symfony regenerate the cache by itself in dev environment only.

    In shorts, try to execute in your console:
    bin/console cache:clear --env=prod

    I'm 99% sure it should solve your problem.

    Cheers!

  • 2017-10-24 Victor Bocharsky

    Hey AbelardoLG ,

    Great, I'd recommend you to do it separately of your code. So if it works from the downloaded archive, then we'll know exactly that the problem in *your* code only, so it'll be easy to debug things further.

    Cheers!

  • 2017-10-24 Victor Bocharsky

    If you don't see this error, so then you should see content of "notes.react.js" file, right? Or, what do you see then in the browser's window when opens http://localhost:8000/js/notes.react.js URL?

  • 2017-10-24 Victor Bocharsky

    2) Great!
    3) I mean open Chrome dev tools -> Network tab and reload the page. If this page not found, you should see 404 status opposite this "notes.react.js". So you can perform right click on this line and choose "Open in new tab". After it, what URL do you have in the browser's address bar? is it "http://localhost:8000/js/notes.react.js"? Do you see an error or content of "notes.react.js" file in opened browser window?

  • 2017-10-24 Victor Bocharsky

    Yes, we add it a bit later, about 3:35. Haven't you seen the video to the end? If not, then what minute have you stuck at?

  • 2017-10-24 AbelardoLG

    4) No, I haven't got that error.

  • 2017-10-24 AbelardoLG

    2) Yes, that file is in that path.
    3) The 404 error isn't showed; simply, that file doesn't appear in the list of downloaded files.

  • 2017-10-24 AbelardoLG

    In the 2:30 of the screencast, you didn't write this line:
    var notesUrl = '{{ path('genus_show_notes', {'genusName': name}) }}';

  • 2017-10-24 AbelardoLG

    Here is the link: http://abelardolg.imgur.com

  • 2017-10-24 AbelardoLG

    Hi Victor,
    Yes, I followed screencasts step by step but I didn't run it from finish/ directory. I will do it.

  • 2017-10-24 Victor Bocharsky

    Hey AbelardoLG ,

    Hm, I just double check it and it works for me well, i.e. browser is able to download "js/notes.react.js" file. I downloaded the course code, install composer deps and run "bin/console server:run" - that's it. So let's debug your code a bit. We include this file in one spot only: in "genus/show.html.twig" template.

    1. Could you make sure you have: "<script type="text/babel" src="{{ asset('js/notes.react.js') }}"></script>" exact line in "javascripts" block of that template? The full content of this block is:


    {% block javascripts %}
    {{ parent() }}
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>

    <script type="text/babel" src="{{ asset('js/notes.react.js') }}"></script>
    <script type="text/babel">
    var notesUrl = '{{ path('genus_show_notes', {'genusName': name}) }}';

    ReactDOM.render(
    <notesection url="{notesUrl}"/>,
    document.getElementById('js-notes-wrapper')
    );
    </script>
    {% endblock %}

    Is it the same you have?

    2. Next, could you make sure you have this file in "web/js/notes.react.js" path?

    3. Also, try to debug 404 error in Google Chrome dev tools, i.e. right click on "notes.react.js" -> "Open in new tab". What URL do you have? it should be exactly "http://localhost:8000/js/notes.react.js". Is it true for you?

    4. Do you have Symfony's 404 error, i.e in the dev mode you should see something like:
    > No route found for "GET /js/notes.react.js"

    Try to follow those debug instructions step by step, I bet we'll fix it together. If you still have the same problem in the end, then provide some answers on my questions so I can move forward.

    Cheers!

  • 2017-10-24 Victor Bocharsky

    I think it could be a problem related to version, but I'm not sure yet. Btw, did you download the course code and ran it from finish/ directory? Or, did you follow screencasts step by step and write all the code we show by yourself?

  • 2017-10-24 Victor Bocharsky

    Hey AbelardoLG ,

    Hm, I'm going to investigate the problem. What about screenshots - we do not allow to upload screenshots in Disqus comments, but you can upload it to any cloud, e.g. https://imgur.com/ and send a link to it in comments.

    Cheers!

  • 2017-10-23 AbelardoLG

    The following files are only loaded: 'main.js' and 'jquery'.

    I am using Opera 48.0.2685.39 on MAC OS El Capitan. It also happens in Google Chrome 61.0.3163.100.

    Could be happen due to the newest version of React, jQuery or anything else?

    Best regards, @Victor Bocharsky

  • 2017-10-23 AbelardoLG

    Hi Victor Bocharsky ,
    Thanks you for replying quickly.

    It seems like that file isn't loaded by the browser.
    How could I upload a screenshot of this issue?

    Best regards.

  • 2017-10-23 Victor Bocharsky

    Hey AbelardoLG ,

    What do you mean on "file doesn't load"? The file could not be found by your browser? Do you see 404 error for this file in "Network" tab og Google Chrome Dev Tools? We would love to help you fix this problem.

    Cheers!

  • 2017-10-20 AbelardoLG

    Hi,
    A year has passed of this tutorial but I would like to mention that the 'notes.react.js' file doesn't load.

    What's wrong?

    NICE AND WONDERFUL TUTORIAL!

    Kindest regards,

  • 2017-09-19 Victor Bocharsky

    Hey Rich,

    Thank you for your feedback and kind words! It gives us strength to make more awesome tutorials. And I'm glad you settle down a little those crazy at the first glance relationships between PHP, Symfony, JS, etc. ;)

    Cheers!

  • 2017-09-18 Rich Wilx

    Knowing that Symfony/Twig/JS et al. held the answers for my new project, and being left even more confused by other tutorials, I finally stumbled on this series. Now, after a couple of hours following these vids, I finally get the relationship between PHP, Symfony, Twig, and JS, and - although I think I've just seen the tip of the iceberg - I'm very excited about learning more....

    Thanks!

    ps. Awesome presentation style too....

  • 2017-07-31 weaverryan

    Milan Vlach you just made my day!!! What an awesome story - you ROCK!!! :) :) :)

  • 2017-07-29 Milan Vlach

    Hey, I don't agree. Your tutorials are so awesome! It helped me so much when I was joining my company. None else can describe so many things in such a cool way, as you do - AND - You motivated me to take a look at reactJS back in the day. Now I have been working in symfony for more than half year, every day and all because of this series of tutorial you have created. I like to rewatch them solely because of nostalgia purposes and quality it holds! :)

  • 2017-07-13 weaverryan

    Yea... I regret throwing React in here - the JavaScript isn't really the point of this tutorial and it trips people up :).

  • 2017-07-12 Marco Koopman

    Good tutorial but it would be easier to follow with just an JQuery AJAX call instead of the react stuff! I will have to follow the React course too to understand it I guess :P

  • 2017-07-12 Victor Bocharsky

    Hey Marco,

    It depends, but most often you need to *add* something new instead of completely override it. Actually, it allows you avoid code duplication. Probably for a simple jQuery it's not so obvious, but suppose you need a lot of scripts like jQuery, Twitter Bootstrap, Sweetalert for nice JS alerts, etc to load on *each* page. You could copy this code from one template to another, but template inheritance is a nice tool to be used in this case which help you to avoid copy/paste. And if some day you change your mine what tools you need - you will need to tweak the only one spot. In shorts, Twig supports template inheritance and it's a very cool to use it in some cases.

    Cheers!

  • 2017-07-12 Marco Koopman

    I dont' understand why you would want to overwrite a block but keep it's content. Isnt it better to just make a new block and put your JS there?

  • 2017-07-10 Diego Aguiar

    Hey Moises Cano

    Yes and no, usually you define a route and attach it's action to a controller's method, but then the only job that the controller must do is to return a "Response" object, it can be the same rendered template, a JSON response, or even an empty response.
    What I'm trying to say is you can handle your routes however you want as long as you stay consistent

    Cheers!

  • 2017-07-10 Moises Cano

    I'm confused by the routing and controllers. I thought a route pointed to a specific page in an app. And the controller handled anything that happened in the route. In GenusController there are two routes basically pointing to the same "page". Am I understanding this correctly?

  • 2017-07-07 Josk

    Hi, It doesn't show the note section at all. I see everything except that part. I'm using the same font style and colour of this tutorial and I saw that the <notesection/> has a different colour (yellow).
    http://i.imgur.com/tCFmdiq.png
    When I put the mouse over it , the popup message says "JSX is used without importing React. When using JSX, it's usually required to have import from React in the file scope. Otherwise, the code may not compile properly."
    What am I missing?
    Thanks

    Solved. Found the error: I didn't close the <script> tag

  • 2017-06-19 Praxitelis Kourtellos

    Hey weaverryan ,

    Yes, that was my mistake, seems I have missed the last part and continued trying fixing it without reading it again.

    Cheers!

  • 2017-06-19 weaverryan

    Yo Praxitelis Kourtellos!

    Ah, I see you added the JSON.parse! You're right that something in JavaScript *does* need to decode the JSON. But, usually jQuery will do it *for* you automatically. It knows to do this automatically when the AJAX endpoint returns a Content-Type: application/json header. When it sees that, it decodes the JSON automatically so that data is already an object. If you find that you need JSON.parse, it's probably because you're not setting the Content-Type header in your Symfony controller. Are you possibly using new Response instead of new JsonResponse in your controller? The nice thing about JsonResponse is that it sets this header for you :).

    Cheers!

  • 2017-06-19 Praxitelis Kourtellos

    For anyone with "Cannot read property 'map' of undefined" this worked:

    loadNotesFromServer: function() {
    $.ajax({
    url: '/genus/octopus/notes',
    success: function (data) {
    this.setState({notes: JSON.parse(data).notes});
    }.bind(this)
    });
    },

  • 2017-05-02 Diego Aguiar

    Hey Islam!

    We are working in a ReactJS tutorial, you can find what's next in our roadmap section
    https://knpuniversity.com/c...

    Cheers!

  • 2017-05-01 Islam Elshobokshy

    This got a liiiitle bit complicated lol

  • 2017-04-18 Julia Shishik

    Yes, you are right! I was missed a comma and l had notesection, not NoteSection. Works with NoteSection! Thank you!!!))

  • 2017-04-17 weaverryan

    Hey Julia Shishik!

    Ah, just saw your follow-up comments. It looks like you figured it all out yourself - awesome :). If you're still having any issues, let us know!

    Cheers!

  • 2017-04-17 weaverryan

    Hey Julia Shishik!

    Hmm. Check your syntax closely against the code we have: https://knpuniversity.com/s.... I can see 2 possible problems:

    A) Make sure you have NoteSection, not notesection
    B) I think you're missing a comma at the end of line 5 - this seems like the most likely issue to me!

    Let me know if that helps! And cheers!

  • 2017-04-16 Julia Shishik

    Thanks! All good!!!

  • 2017-04-15 Julia Shishik

    Error was disappeared but js isn't running like on the foto
    Skanislav • 2 months ago
    Hey there. Seems like my JS code on webpage isn't running. imgur.com/a/TizkE

  • 2017-04-15 Julia Shishik

    Hey there! I have a problem! JS code on webpage isn't running! My error in the Console:

    Uncaught SyntaxError: embedded: Unexpected token (5:8)
    3 | ReactDOM.render(
    4 | <notesection url="{notesUrl}"/>
    > 5 | document.getElementById('js-notes-wrapper')
    | ^
    6 | );
    7 | Please, help me!

  • 2017-04-04 weaverryan

    Cheers! Thanks for the nice words Gremet Laurent! :)

  • 2017-04-03 Diego Aguiar

    Hey Gremet Laurent

    No worries, things like that happens to all of us :)

    Have a nice day!

  • 2017-04-01 Gremet Laurent

    about the page auto refresh :
    it's okay now. the ajax auto refresh didn't work because it needs the page to be focused (i have two screens and was on the other screen when it didn't work).

  • 2017-03-31 Gremet Laurent

    Hi, i also had the img pathj problem because my site wasn't directly under localhost and it works fine, thanks.

    just when i remove one of the notes in the twig file this doesn't make any change on the page untill i refresh it manually. But it doesn't matter for the moment, i'll see it when i'll follow the react course.

    And by the way thank you Ryan, your voice and your attitude make the course really cool and easy, in a "keep it simple" way.

  • 2017-03-28 =METTEK=

    Check your js code in twig file. It's must be;
    <script type="text/babel">
    ReactDOM.render(
    <notesection/>,
    document.getElementById('js-notes-wrapper')
    );
    </script>

    Instead of
    ReactDOM.render(
    <notesection url="{notesUrl}"/>,
    document.getElementById('js-notes-wrapper')
    );

  • 2017-02-14 Victor Bocharsky

    Hey Skanislav,

    Do you use Google Chrome? Could you open "Console" tab (in Chrome menu -> More Tools -> Developer tools) and see what errors you have there? Probably some remote files do not load on the page.

    Cheers!

  • 2017-02-14 Skanislav

    Hey there. Seems like my JS code on webpage isn't running. imgur.com/a/TizkE

  • 2017-01-23 dan-nl

    hey weaverryan,

    my mistake. i must have missed the step that has the GeniusController::getNotesAction() return $data = [ 'notes' => $notes ]; instead of $data = [ $notes ]; changing that return array to the former format took care of the js, which now works with this.setState({notes: data.notes});

  • 2017-01-22 weaverryan

    Awesome - thanks for sharing that!

  • 2017-01-21 edo

    i got the some problem i forgot to use jsonResponde and the header were not set to json that's why the js code had a string as return and cannot work with forcing json evaluate. how ever after i used the correct method ( rememberto to add the use or use the autocomplete ) the script works perfectly .... Edo

  • 2017-01-20 weaverryan

    Hey dan-nl!

    Can you tell me more about this? I cannot repeat (using the code we used on this tutorial) the error that some others are having. From your fix, it looks like the AJAX endpoint is returning a slightly different format than mine did originally - everything *should* be under a "notes" key (see the 3rd code block here: https://knpuniversity.com/s.... Are you seeing something different? If there's something we need to fix - or at least make more clear - I would love to add that!

    Thanks!

  • 2017-01-20 dan-nl

    easiest way to solve the js error is to correct web/js/notes.react.js line 17; change:

    this.setState({notes: data.notes});

    to

    this.setState({notes: data[0]});
  • 2017-01-09 weaverryan

    Hey Olaf!

    Ah, REALLY glad you're learning a lot! Keep going - it will be worth it :). But, I am sorry that I got you stuck on the ReactJS stuff! But, you posted your code for me! That's awesome - it makes debugging this together really nice :).

    In fact, I've fixed the issue and added some comments about it on this PR: https://github.com/Olafkuus.... All the details are there.

    The "map" error itself isn't something specifically from ReactJS. Yes, it's happening on our React file, but .map is a function that you can call on an array. Check out the line where the error is happening: https://github.com/knpunive.... Basically, without jumping into React stuff, this.props.notes should be a JavaScript array. If it *is*, then we can call .map on it. But, your error is reporting that this.props.note is *undefined*. So then the question is, why is this undefined and not an array? The answer *does* require knowing a bit about ReactJS to see where this variable comes from. In this case, it comes from our AJAX call - if that receives an invalid response, then this.props.note will be undefined.

    I hope this helps and gets you back and moving! Keep up the good work!

    Cheers!

  • 2017-01-08 Olaf Kuusik

    Hey Ryan!
    Really great tutorials so far, I've learned a lot and I'm very grateful, but I've stumbled on the ReactJs part twice already.
    I'm building a really similar application parallel to your tutorial (making a contact form with a list output, so I thought I could use the notes part for my contacts, so they would update on the fly like your comments do. The project is purely for study purpose and I hope to learn Symfony through completing an assignment.

    I'm getting the similar error as IronedMonkey and I don't really understand the solution you have given as the answer to him. Could you maybe give me a longer explanation of the problem or lead me to an answer/tutorial about 'map' part of ReactJs. I posted my files on github: https://github.com/Olafkuus.... I would really appreciate If you could help me in any way. I apologize if my code is horrible :)

    The error message I get in the Chrome console:
    Uncaught TypeError: Cannot read property 'map' of undefined
    at Constructor.render (eval at transform.run (browser.min.js:4), <anonymous>:54:46)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (react.js:5943)
    at ReactCompositeComponentWrapper._renderValidatedComponent (react.js:5963)
    at ReactCompositeComponentWrapper.wrapper [as _renderValidatedComponent] (react.js:12346)
    at ReactCompositeComponentWrapper._updateRenderedComponent (react.js:5916)
    at ReactCompositeComponentWrapper._performComponentUpdate (react.js:5900)
    at ReactCompositeComponentWrapper.updateComponent (react.js:5829)
    at ReactCompositeComponentWrapper.wrapper [as updateComponent] (react.js:12346)
    at ReactCompositeComponentWrapper.receiveComponent (react.js:5761)
    at Object.receiveComponent (react.js:13021)

  • 2017-01-04 weaverryan

    Hey @ironedmonkey!

    Ah, sorry for the problems! I'll admit, sticking ReactJS in here wasn't my best idea - I wanted to expose people to it, but it's a bit out of place. Apologies about that! We'll have a separate ReactJS tutorial coming in the future - that's the right place for this stuff!

    About your error, my guess is that the AJAX call that's being made to the server to return the notes is somehow failing (or returning an unexpected response). On load, we make an AJAX call (https://github.com/knpunive.... This should return JSON with a "notes" key, which is then used (https://github.com/knpunive.... It looks like the JSON coming back from the server may not contain a "notes" key, which causes things to fail later. But, if you're not interested in ReactJS, then I wouldn't worry about this part too much - the most important thing for Symfony was for us to make an endpoint that returned JSON. Using ReactJS was a way to show how that might be used on the frontend to update things.

    Let me know if that helps!@ I'm glad you've enjoyed the rest of the tutorial!

    Cheers!

  • 2016-11-24 weaverryan

    Hey Xeyos!

    I've never tried it (though I've seen PhpStorm advertise this), but my guess is, yea! It should work just fine :). The reason I don't use it is that it seems that if you need Babel to transforms ES6 to ES5, then you probably will also want to go a step further and use a module bundler like webpack so that you can use require/import statements. We use webpack here on KnpU, and it takes care of the Babel transformation. But, the water seems like a great idea to me if you don't need a bundler!

    Cheers!

  • 2016-11-24 Xeyos

    Hi weaverryan,
    A simple question, you use File watcher 'Babel' whit PhpStorm?

  • 2016-10-24 weaverryan

    Awesome! Let me know if you have any questions :)

  • 2016-10-23 Andrada Ganesha

    Hello Ryan,
    I will modify the project to include webpack and prepare the environment for production. Thank you for your suggestions and support!

  • 2016-10-22 weaverryan

    Hey Andrada!

    I know you have it working now, but I wanted to answer this here, in case others wonder. So... basically... yes! In this tutorial, we use React in a *very* simple way - more simple than should be used on production. In reality, using ReactJS is a bit more complex - it really requires a "build" step and a tool like webpack (or browserify) to do that. It's a big giant topic - you may have seen a presentation I gave at Symfony.cat about this - and one that we're going to start covering here over the next few months. React and Symfony are an awesome combination... but there's a lot of stuff to learn and setup before you can really dig into it.

    Cheers!

  • 2016-10-22 weaverryan

    Great job Andrada! The problem/solution doesn't make total sense to me (what you were doing originally *sounds* correct, also), but it's not important - we're just using ReactJS here as a nice example.

    Cheers!

  • 2016-10-21 Andrada Ganesha

    Hello Ryan,

    I discovered what the problem was.
    I inserted the all the scripts including jquery and reactjs path in base.html.twig and in show.html.twig I put {{ parent() }} in the
    javascripts block, but for some reason the ajax calls were not working with this configuration.
    I updated the files and inserted jquery in base.html.twig and reactjs inserted in show.html.twig and now the code
    is working and the notes section gets loaded with the pictures showing up perfect.

    Thank you for your precious support!
    Andrada

  • 2016-10-21 Andrada Ganesha

    Hello Ryan,

    I think the ajax call is failing.
    I have all the files configured as indicated in the tutorial.
    Is it necessary to use webpack?
    I saw this in ar article related to symfony and reactjs.
    I think I am missing something.

    Thank you!
    Andrada

  • 2016-10-21 weaverryan

    Hey Andrada!

    Ok, 2 things. First, the JSON itself looks perfect, so I think that your route and controller are probably awesome :).

    Second, if you go directly to the URL you posted, you *should* just see plain JSON in your browser - without any styling or images (sure, there's an image path with avatarUri - but your browser is dumb and just shows JSON). So, that's actually ok! We do that in this chapter: https://knpuniversity.com/s... - by the end, we just see JSON. My JSON might be a little prettier than yours, but that's thanks to a browser plugin called JsonView, which just "pretty-ifies" JSON in my browser so I can read it better).

    But, you should be able to make an AJAX call to this endpoint (we do it inside React), then use the data to update the HTML on the page (React handles this), and this updated HTML *should* be styled and show the avatar image. Are you making the AJAX call? Is that where things fail?

    Let me know!

  • 2016-10-21 Andrada Ganesha

    Hello Ryan,

    Thank you for responding on this matter.
    My url is locally on MAMP: http://blogsymfony.dev/mysy...
    And it just print the JSON response to the browser that is:

    {"notes":[{"id":1,"username":"AquaPelham","avatarUri":"\/mysymfony\/web\/images\/leanna.jpeg","note":"Octopus asked me a riddle, outsmarted me","date":"Dec. 10, 2015"},{"id":2,"username":"AquaWeaver","avatarUri":"\/mysymfony\/web\/images\/ryan.jpeg","note":"I counted 8 legs... as they wrapped around me","date":"Dec. 1, 2015"},{"id":3,"username":"AquaPelham","avatarUri":"\/mysymfony\/web\/images\/leanna.jpeg","note":"Inked!","date":"Aug. 20, 2015"}]}

    and no other content.
    Any idea what I am doing wrong here?

    Many thanks!
    Andrada

  • 2016-10-21 weaverryan

    Hi Andrada!

    Awesome - and nice work practicing with this stuff :). Oh, and I love FOSJsRoutingBundle - so +1 for using that!

    About your issue, the code you have and what you're describing sounds ok, so I'm guessing we have some minor issue. First, your genus_show_notes endpoint *does* return JSON, correct? And in that JSON, there is an avatarUri field for each note, correct? If so, is the problem simply that when you parse the JSON in JavaScript, the resulting HTML has a missing avatar? Or are there other issues?

    Let me know - I'm not sure that I'm fully understanding (and so answering) the *exact* issue that you're having.

    Cheers!

  • 2016-10-19 Andrada Ganesha

    Hello Ryan,

    I enjoyed the tutorial and played with it in a small app.
    Problem is I am getting just the json response printed out at /genus/show/notes endpoint, no styling or pictures.
    I am using Symfony 2.8. Should I update to Symfony 3.1.2?
    I used FOSJsRoutingBundle and in routing.yml I am declaring this:

    genus_show_notes:
    pattern: /genus/{genusName}/notes
    defaults: { _controller: AppBundle:Genus:getNotes }
    options:
    expose: true

    Can you point me in the right direction?
    What am I doing wrong?

    Thank you!

  • 2016-10-19 weaverryan

    Hey Claudio!

    Ah, you're right - my answer above is a bit too "ahead" - it applies to how your code would look after the Doctrine relations tutorial when we make the notes dynamic! For now, it should look something like this:


    // in GenusController::getNotesAction()
    // ...

    // JUST change the avatarUri value on each line
    $notes = [
    ['id' => 1, 'username' => 'AquaPelham', 'avatarUri' => $this->get('assets.packages')->getUrl('/images/leanna.jpeg'), ...],
    ['id' => 2, 'username' => 'AquaWeaver', 'avatarUri' => $this->get('assets.packages')->getUrl('/images/ryan.jpeg'), ...],
    ['id' => 3, 'username' => 'AquaPelham', 'avatarUri' => $this->get('assets.packages')->getUrl('/images/leanna.jpeg'), ...],
    ];

    Let me know if that works! This does the same thing as the {{ asset() }} function in Twig, which simply corrects for the sub-directory where you have Symfony installed (e.g. /ProjectNme/web in your case).

    Cheers!

  • 2016-10-19 Claudio

    Hey!

    I had the same problem as Maxime and I solved it by adding the "/ProjectNme/web" to the avatar Urls.
    But I would like to do it with your function of getUrl you have there. When I put it, symfony returns an error saying that the variable note was not defined.
    I assume that this ".$note->getUserAvatarFilename() is the problem, I tried by changing $note for $notes (just trying to see whether it works) but I got no positive results.

    Thanks for this amazing tutorials!
    Cheers

  • 2016-10-14 bananaaus

    A bit late in the game but I just did this course and really enjoyed it. I had the same error. This was caused by not having your data as an associative array named 'notes' in getNotesAction() of the controller.

    So, instead of :

    $data = [ $notes ];

    It has to be:

    $data = [ 'notes' => $notes ];

    This is correct in the 'finish' code.

  • 2016-10-06 weaverryan

    Yep, the JsonResponse class should do all of this for you, but if you ever use the Response object directly with json_encode, definitely don't forget to set the Content-Type header exactly as Abou said: this is what tells JavaScript how to parse the response.

    Cheers!

  • 2016-10-06 Abou

    Mybe you're using the response methode withe the json_encode function like this :
    $response = new Response(json_encode($data,JSON_UNESCAPED_UNICODE));

    In this case you should set the content type this way :
    $response->headers->set('Content-Type', 'application/json');

    If you don't the ajax response won't parse as json then notes won't be defined.

    I had the same problem and fixed it as I mentionned !

    Cheers !

  • 2016-09-30 Diego Aguiar

    You are awesome, thanks again for your help, as always it is very appreciated

    :D

  • 2016-09-30 weaverryan

    Hey Diego!

    You're to an awesome step then :). We will have a React.js tutorial with Symfony eventually, but don't wait for us :). My best advice is that there shouldn't be anything too special: just treat Symfony is your API. You can even still login with a traditional form if you want to, and allow your JS to authenticate via a normal session cookie. Or you can use a token system like we talk about in some places here.

    Also, I did a presentation on this somewhat recently - some parts of it might help: https://youtu.be/iINLewCGnuY

    Cheers!

  • 2016-09-27 Diego Aguiar

    Hello Ryan! How you doing ?

    Thank you for this tutorials, I've learnt a lot, I finally released my first project going full with symfony
    Now, I'm going to improve my UI by using React.js , but I just can't find good tutorials showing how to integrate Symfony and React.js properly

    If you know any good tutorial which you want to share, would be very helpful and appreciated, or even better if you make one!

    Thanks ;]

  • 2016-09-26 weaverryan

    Yea, we threw it in as an extra :) - there's definitely a lot more you need to know to actually use React (and jQuery would be a lot simpler for this use-case). But, really glad you liked the course, and thanks for the kind words - awesome!

    Cheers!