-2

Here is a div that I append in AJAX with a script (at the bottom of the TWIG file) :

    <div>
        {% for vote in proposal.votes %}
            {% if app.user == vote.user %}
                <a href="{{ path('vote_delete',{'proposal' : proposal.id, 'vote' : vote.id}) }}" 
                    class="btn btn-light ml-1 btn-sm">
                </a>
            {% endif %}
        {% endfor %}
    </div>

If I then click on the freshly appended button, it returns an error because the ID "vote.id" is still 0 until I reload the page and the ID gets found...

Is there a way to trigger the for loop without reloading the page to get the ID directly after its creation? Is it linked with "async" or any "ready" function?

EDIT :

The script that appends the div #deleteVote when I vote :

$(document).on('click', '.votedFullAgreement', function (event){
    event.preventDefault();
    $.ajax({
        url: '{{ path('vote_add', {'slug' : slug, 'proposal' : proposal.id, 'userVote' : 'votedFullAgreement', 'user' : app.user.id }) }}',
        type: 'POST',
        dataType: 'html',
        success: function (){
            if( $('#deleteVote').length === 0 ) {
                //The whole HTML of the div
        },
        error: function (resultat, statut, erreur) {
            console.error(erreur);
        }
    });
});

The #deleteVote that gets appended, with the url of the "deleteVote" function (which needs to know the ID of the vote to delete) :

$(document).on('click', '.deleteVote', function (event){
    event.preventDefault();
    $.ajax({
        url: '{{ path('vote_delete', {'slug' : slug, 'proposal' : proposal.id, 'vote' : vote.id }) }}',
        type: 'POST',
        dataType: 'html',
        success: function (){
            $('#deleteVote').slideUp();
        },
    });
});
vLk171x
  • 11
  • 5
  • This looks like a *server-side* templating system. So "trigger the `for` loop" may be the wrong approach entirely. When you modify the DOM client-side, what specifically are you doing? If the problem is that the `href` value is incorrect, what value are you setting for it and how is that value incorrect? – David Oct 10 '22 at 16:42
  • Create all the paths at start, then assign them a `data-path` attribute which you then can access in JS – DarkBee Oct 10 '22 at 16:49
  • Does this answer your question? [Twig variable in external JS file](https://stackoverflow.com/questions/37604063/twig-variable-in-external-js-file) – DarkBee Oct 10 '22 at 16:50
  • @David This is a voting system ; when a "voteButton" gets clicked, the vote gets persisted to the DB in the controller (with info such as the ID of the proposal, the ID of the voter etc), and a "deleteVoteButton" appears. The problem is that when the "deleteVoteButton" appears, in AJAX, it doesn't know **yet** the ID of the vote just sent, and thus the full URL to delete it : `/{slug}/workshop/proposal/{proposal}/vote/delete/{vote}` – vLk171x Oct 10 '22 at 16:51
  • @vLk171x: Then it sounds like that AJAX operation, and/or the JavaScript code invoking or responding to it, isn't successfully populating the `href` when adding a new link to the DOM. But, again, that code isn't shown in the question. *In general*, the operation which creates a new record should return at least the ID for that record (or potentially the entire record) and the client-side code would use that information to update the DOM. If your code isn't doing that, you might change it to do that. – David Oct 10 '22 at 16:54
  • @DarkBee Not really as I know the path and how to access the variable, except for the ID at the end of the URL... The object gets created but can't be deleted directly as its ID is not known yet... – vLk171x Oct 10 '22 at 16:59
  • That's why you need to calculate ALL of the paths otherwise you can't solve this without ajax – DarkBee Oct 10 '22 at 17:00
  • @David Thanks for the replies. I don't know what part of the code I could add to my original post to make it clearer... The `vote.id` is like 615 or whatever it is in the DB, and when I reload the page, it works, I can access it and delete and all. It's just that I feel like I'm trying to delete something that doesn't even exist yet or before the ID is returned (it's my first AJAX scripts...) – vLk171x Oct 10 '22 at 17:05
  • @vLk171x: Are you saying there's no code which performs an AJAX operation and updates the DOM with the new "delete button"? If the code shown in the question is the only code which produces these buttons then I guess it's not clear to me what the problem is. Does `proposal.votes` not have the data you expect when this code executes? Where is it getting that data? Basically *the code shown* isn't doing anything wrong. You keep alluding to other code, but then indicate that there's no other relevant code to show. – David Oct 10 '22 at 17:08
  • @David Yeah sorry let me edit the post and add the JS function. When I haven't voted yet, `proposal` doesn't contain any `vote`. So the problem to me is that this `for` loop gets triggered only after voting **and** reloading the page because it then finds one vote to get the ID of, but I don't understand how to get it directly in AJAX – vLk171x Oct 10 '22 at 17:18
  • ... You can't pass any javascript variable to twig/php without ajax - [Difference between clientside and serverside](https://stackoverflow.com/questions/13840429/what-is-the-difference-between-client-side-and-server-side-programming) – DarkBee Oct 10 '22 at 17:26
  • @vLk171x: *"The script that appends the div"* - Isn't appending anything to a div. It does, however, demonstrate a variety of syntax errors. The first thing you're going to want to do is separate your *server-side* code from your *client-side* code. Whatever client-side code you're trying to debug, look at the actual resulting client-side code and not just the server-side code which creates it. Aside from that, start with basic debugging. For the operation which fails, observe its inputs. If any one of those inputs isn't what you expect, debug where that input comes from. Etc. – David Oct 10 '22 at 17:30
  • @vLk171x: For example... If the operation that fails is an AJAX call to delete a record, and it fails because it doesn't receive the ID for that record, then for that specific operation where does that ID come from? Is it from the URL being invoked? If so, what builds that URL? Where does *that* logic get the values to use for building that URL? And so on. Eventually, if you follow the trail step by step, you would encounter an operation which has the expected inputs and produces an unexpected output. *That* is where we can help. – David Oct 10 '22 at 17:38
  • @DarkBee That's basically AJAX I am trying to do... I'd like to be able to vote then to delete the vote then to vote again etc without reloading the page once. The problem is also certainly that the variable I am trying to reach is created inside a `for` loop and is accessible only inside it... @David Yeah I get it, well, I hope I do... Thank you for your patience – vLk171x Oct 10 '22 at 18:02
  • No it's not, as i said you can't pass js variables to twig. You need to send an extra request to fetch the path – DarkBee Oct 10 '22 at 18:07
  • @DarkBee Do you mean a fetch request like that? https://stackoverflow.com/questions/67951670/pass-variables-in-url-path-to-fetch-get-request After the vote function and before the delete function – vLk171x Oct 10 '22 at 19:00
  • @vLk171x: The root of the problem appears to be a fundamental misunderstanding on your part regarding client-side code vs. server-side code. All we can really describe is *general approaches* to using AJAX, which you'd be able to get from tutorials and examples online. You're going to need to do some debugging to narrow down the specific problem in your code. But it appears that, in order to do this, you're going to need more research and practice to understand what your code is doing in the first place. – David Oct 10 '22 at 19:17

1 Answers1

0

As I've mentioned in the comments, you can't pass a javascript directly to twig, as twig is rendered serverside. One way to solve this is to calculate all the path beforehand:

{% for vote in proposal.votes %}
    ...
    <button type="button" class="votedFullAgreement" data-path="{{ path('vote_add', {'slug' : slug, 'proposal' : proposal.id, 'userVote' : 'votedFullAgreement', 'user' : app.user.id }) }}">Add vote</button>
    ...
{% endfor %}

Now you can access the path directly in javascript

$(document).on('click', '.votedFullAgreement', function (event){
    event.preventDefault();
    $.ajax({
        url: $(this).data('path'),
        type: 'POST',
        dataType: 'html',
        success: function (){
            if( $('#deleteVote').length === 0 ) {
                //The whole HTML of the div
        },
        error: function (resultat, statut, erreur) {
            console.error(erreur);
        }
    });
});

You could also make an extra request to a controller to generate the path, but this would mean you would need to pass all the variables, e.g. slug, app.user.id, ...

More information on how to generate a path inside a controller can be found here

DarkBee
  • 16,592
  • 6
  • 46
  • 58