title: Write data to cookie via javascript in a Django project
body: <p>In my Django project, have a MPTT Model called Workspace (&quot;Dossier&quot;, in french). Like directories in a computer, workspaces can be nested together.</p>
  <p><img src="https://i.stack.imgur.com/ntK2W.png" alt="Workspaces view" /></p>
  <p>Workspaces are then displayed to users as shown in the previous screenshot, like a tree.</p>
  <p>By default, all workspaces are expanded. When user click on the &quot;-&quot; sign, children workspaces disappear, and conversely when click on &quot;+&quot;. This is handled by javascript.</p>
  <p>This is working great. However, i'd like tree state to be saved when user refresh the page, so that he does not need to expand/collapse everything again.</p>
  <p>I know I could do this via ajax : clicking on &quot;-&quot; or &quot;+&quot; would send a request to the server, storing the pk of the workspace and the user in database with the state. It seems very complex to me, and it won't work with anonymous users.</p>
  <p>A better idea would be to handle this with cookies, but I'm obviously doing some stupid mistake writing the javascript code. Here is were i'm gone so far :</p>
  <pre><code>$( document ).ready(function() {
      
      // from http://ppk.developpez.com/tutoriels/javascript/gestion-cookies-javascript/
      // these are sample functions to write/read cookies took from a tutorial
  
      function createCookie(name,value,days) {
          if (days) {
              var date = new Date();
              date.setTime(date.getTime()+(days*24*60*60*1000));
              var expires = &quot;; expires=&quot;+date.toGMTString();
          }
          else var expires = &quot;&quot;;
          document.cookie = name+&quot;=&quot;+value+expires+&quot;; path=/&quot;;
      }
  
      function readCookie(name) {
          var nameEQ = name + &quot;=&quot;;
          var ca = document.cookie.split(';');
          for(var i=0;i &lt; ca.length;i++) {
              var c = ca[i];
              while (c.charAt(0)==' ') c = c.substring(1,c.length);
              if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
          }
          return null;
      }
  
      function eraseCookie(name) {
          createCookie(name,&quot;&quot;,-1);
      }
  
  
      function arrayToCookie(array){ // convert an array to cookie format (coma separated list)
          return array.join(',');
      }
      function cookieToArray(cookie){
          return cookie.split(','); // convert a coma-separated cookie to an array
      }
  
  
      var expanded_workspaces_cookie_name = &quot;expandedWorkspaces&quot;;
  
      // create the cookie if it does not exists
      // The cookie is basically a list of workspaces id that are expanded, written like this : &quot;1,3,12,157&quot;
      function initExpandedCookie(){
          console.log(&quot;init cookie&quot;);
          console.log('read',document.cookie, readCookie(expanded_workspaces_cookie_name));
          console.log(typeof($.cookie(expanded_workspaces_cookie_name)));
  
          if (!readCookie(expanded_workspaces_cookie_name)) {
              console.log(&quot;new cookie&quot;);
              createCookie(expanded_workspaces_cookie_name,'', 365);
          }
          else {
              console.log(&quot;cookie already exists&quot;);
          }
      }
  
      initExpandedCookie();
  
      function setExpandedWorkspaceToCookie(id, add){
          console.log(&quot;id =&quot;, id, typeof(id), id.length);
          var w = readCookie(expanded_workspaces_cookie_name);
          console.log('Value of old cookie',document.cookie);
          var s = cookieToArray(w);
          console.log(&quot;Id array before&quot;, s);
          if (add === true) { // Add the id to the list of expanded workspaces, in cookie
              console.log('Add workspace to expanded list');
              s.push(id);
              console.log(&quot;Id array after add&quot;, s);
          }
          else { // remove the id from the list of expanded workspaces, in cookie
              console.log('Remove workspace from expanded list');
              s.splice(s.indexOf(id));
          }
          console.log(&quot;Id array after&quot;, s);
          eraseCookie(expanded_workspaces_cookie_name); // empty existing cookie
          console.log('Values to insert into cookie', arrayToCookie(s));
          createCookie(expanded_workspaces_cookie_name, arrayToCookie(s), 365); // add id lists to cookie
          console.log('Value of new cookie',document.cookie );
  
      }
      function collapse(e, update_cookie) {
          e.addClass(&quot;collapsed&quot;);
          e.removeClass(&quot;expanded&quot;);
          e.find('ul.children').hide();
          if (update_cookie==true){
              setExpandedWorkspaceToCookie($(e).attr('id'), false);
          }
      }
      function expand(e, update_cookie) {
          e.addClass(&quot;expanded&quot;);
          e.removeClass(&quot;collapsed&quot;);
          e.find('ul.children').show();
          if (update_cookie==true){
              setExpandedWorkspaceToCookie($(e).attr('id'), true);
          }
      }
  
      $('#workspaces.widget .parent.expanded').each( function(index){
          expand($(this)); // Set up already expanded workspaces, so don't update cookie
      });
      $('#workspaces.widget .parent.collapsed').each( function(index){
          collapse($(this)); // Set up already collapsed workspaces, so don't update cookie
      });
      $('#workspaces.widget .parent .collapse').click(function() {
          collapse($(this).closest('.parent'), true); // Trigger when clicking on &quot;-&quot;, so update cookie
      });
      $('#workspaces.widget .parent .expand').click(function() {
          expand($(this).closest('.parent'), true); // Trigger when clicking on &quot;-&quot;, so update cookie
      });
  
  }); 
  </code></pre>
  <p>When I test it in browser (collapse/expand on some workspaces), javascript console outputs :</p>
  <pre><code>init cookie 
  read expandedWorkspaces=; csrftoken=bnR6E6s2CtjCTYEyl5reGTijR3mFXdLF  
  string 
  new cookie 
  id = 220 string 3 
  Value of old cookie csrftoken=bnR6E6s2CtjCTYEyl5reGTijR3mFXdLF; expandedWorkspaces= 
  Id array before [&quot;&quot;] 
  Remove workspace from expanded list 
  Id array after [] 
  Values to insert into cookie  
  Value of new cookie csrftoken=bnR6E6s2CtjCTYEyl5reGTijR3mFXdLF; expandedWorkspaces= 
  id = 220 string 3 
  Value of old cookie csrftoken=bnR6E6s2CtjCTYEyl5reGTijR3mFXdLF; expandedWorkspaces= 
  Id array before [&quot;&quot;] 
  Add workspace to expanded list 
  Id array after add [&quot;&quot;, &quot;220&quot;] 
  Id array after [&quot;&quot;, &quot;220&quot;] 
  Values to insert into cookie ,220 
  Value of new cookie csrftoken=bnR6E6s2CtjCTYEyl5reGTijR3mFXdLF; expandedWorkspaces=,220
  </code></pre>
  <p>I try to store the list of expanded workspaces in the cookie as a coma-separated list. For some reason, it inserts an empty string in the list. Moreover, when expanding a workspace, instead of adding it's ID at the end of the cookie, it simply replace the whole cookie with it's ID.</p>
  <p>You can test it live (with Javascript console open) here : <a href="http://kii.eliotberriot.com/test/items" rel="nofollow noreferrer">http://kii.eliotberriot.com/test/items</a></p>
  <p>Also, is there a more efficiant way to handle this kind of things that what i'm doing ?</p>
  <p>Thank you for your help, just tell me if you need more informations !</p>