Search code examples
javascriptjqueryajaxsymfonysymfony-3.4

Send a modified json from the view to controller


At the moment I have in my view an editable table, created from a starting json with a javscript function. In this table it is possible to change every single field of the json. I am currently looking for a way to pass this user-edited json once a button is clicked. The problem is that I've never done an Ajax call...

First of all this is my view:

{% extends 'default/index.html.twig' %} 
{% block content %}
    <div class="json-view">   <!-- here is where I print my table -->

    </div>
{% endblock %}
{% block javascripts %}
    // Here is where I execute all the function below
{% endblock %}

This is my starting json:

[{"a" : 0, "b" : 7, "c": "/", "d" : 5, "e" : "/", "f" : 5,  "g" : "/"},
{"a" : 0.1, "b" : 15, "c": 30, "d" : 10, "e" : 30, "f" : 10,  "g" : 30},
{"a" : 0.2, "b" : 15, "c": 30, "d" : 10, "e" : 30, "f" : 10,  "g" : 30},
{"a" : 0.3, "b" : 15, "c": 30, "d" : 10, "e" : 30, "f" : 10,  "g" : 30},
{"a" : 0.4, "b" : 15, "c": 30, "d" : 10, "e" : 30, "f" : 10,  "g" : 30},
{"a" : 0.5, "b" : 15, "c": 30, "d" : 10, "e" : 30, "f" : 10,  "g" : 30},
{"a" : 0.6, "b" : 20, "c": 30, "d" : 20, "e" : 30, "f" : 15,  "g" : 30},
{"a" : 0.7, "b" : 20, "c": 30, "d" : 20, "e" : 30, "f" : 15,  "g" : 30}]

This is the javascript function that I've used for creating the editable table:

function jsonToTable(json, opts={}) {
  let headers = Object.keys(json[0]);
  let table = document.createElement('table');
  let thead = document.createElement('thead');
  let tbody = document.createElement('tbody');
  let thead_tr = document.createElement('tr');
  if (opts.class) table.classList.add(opts.class);
  headers.forEach(header => {
    let th = document.createElement('th');
    th.textContent = header;
    thead_tr.appendChild(th);
  });
  json.forEach(record => {
    let tr = document.createElement('tr');
    headers.forEach(field => {
      let td = document.createElement('td');
      td.textContent = record[field];
      td.setAttribute('contenteditable', true);
      tr.appendChild(td);
    });
    tbody.append(tr);
  });
  thead.appendChild(thead_tr);
  table.appendChild(thead);
  table.appendChild(tbody);
  return table;
}

And this is the function that i use to take back the edited value from the table:

function tableToJson(table, options={}) {
  let fields = Array.from(table.querySelectorAll('thead tr th')).map(th => th.textContent);
  return Array.from(table.querySelectorAll('tbody tr')).map(tr => {
    return Array.from(tr.querySelectorAll('td')).reduce((record, td, index) => {
      return Object.assign(record, { [fields[index]] : formatValue(td.textContent) });
    }, {});
  });
}

I have to return the table to the controller because I have to modify it in the latter and save it in my database.

Are there any ways to do that?


Solution

  • Sure you can! This is the ajax call:

    $.ajax({
      url : "path('ajax_call_for_table')",
      type: "POST",
      data : table_data,
      success: function() { // some code on success }
    });
    

    Where table_data is the data that you want to modify.

    Then, you have to create a method in your controller to handle this ajax call:

    /**
     * @Route("/ajax/table-data", name="ajax_call_for_table")
     * @Method("POST")
     */
    public function setTableData(Request $request)
    {
        if ($request->isXmlHttpRequest()) { // <- Check that is an ajax call
            $em = $this->getDoctrine()->getManager();
    
            $table_data = $request->request->get('table_data'); // <- Get the *data* of ajax
    
            /** Do something with this data */
    
            return new Response();
        }
    }
    

    Note that the name of this method have to be the same that you use in the url of ajax call.

    Sorry form my englis.