0

I'm trying to make the contents of a <div contenteditable="true"> saved to the db in my Rails app through a form, so it can be saved and updated by the user.

Here is the setup:

The user gets a view (i.e /posts/1) that includes a <div> with contenteditable= "true". I added the javacript to give me a 'Save' button and a hidden field that will capture the content of the div for saving, as suggested in Can div with contenteditable=true be passed through form?. Then changed it to follow the suggestions in this same question.

<%= form_for @post do |form| %>                                                    
        <%= form.hidden_field :content %>
        <%= form.submit "Save" %>
    <% end %>
<div id="content" contenteditable="true">
    <p>Hello</p>
</div>
<script>
        document.getElementById('content').addEventListener('input', function(ev){
  document.getElementById('post_content').value = ev.target.innerHTML;
})
</script>

The behavior I'm looking for is for this form to, once I press 'Save', save all the contents of <div id="content"> to @post.content

I've added :content to my post_params in posts_controller.rb

def post_params
      params.require(:post).permit(:user_id, :content)
end

But it doesn't work. @post.content stays as nil as ever.

Server logs shows that the param :content is being sent, but empty!

Started PATCH "/posts/3" for ::1 at 2019-10-01 19:36:24 +0200
Processing by PostsController#update as HTML
  Parameters: {"authenticity_token"=>"SRzcfcrBWOCdaWeJkp6rCRw94Ex2XLuVvnc3Bt1dFP1JFz36NCNTcxcuOVqzymlIGq9sveaE/+OkDnaHv3kJNQ==", "post"=>{"content"=>""}, "commit"=>"Save", "id"=>"3"}

Any guesses of what am I doing wrong? Thanks in advance

brobert
  • 43
  • 4

2 Answers2

1

You are setting the value the wrong way. You want to set the "post_content" value to the "content" innerHTML.

document.getElemenetById('post_content') = document.getElementById('content').innerHTML;

Also, you should use a hidden input instead of a textarea with display:none.

And lastly, make sure the function is being triggered. I don't think the "onsubmit" callback is properly fireing since form_with intercepts the form submission and does an ajax request.

Personally I'd listen to the input event on the contenteditable element so you don't depend on the form submission:

document.getElementById('content').addEventListener('input', function(ev){
  document.getElementById('post_content').value = ev.target.innerHTML;
})

Now everytime you change the contenteditable content you get the input updated instantly.

arieljuod
  • 15,460
  • 2
  • 25
  • 36
  • Thank you for the many comments and suggestions! (neat idea to listen to the input) I've been trying more stuff to debug this and actually I think the problem runs deeper. It's not only the function not being triggered, or the values being exchanged. Even if I unhide the textarea and try to update it by hand it wont work. So something else is wrong. Once I find out I'll go through your answer again. Thanks! – brobert Oct 01 '19 at 16:29
  • Use a hidden input, not a normal input with display: none. Also check the server log, look what are you receiving on the params hash. – arieljuod Oct 01 '19 at 16:46
  • back in track. param :content is not being sent so I guess the function is fireing. I guess I should use the form_for helper instead of form_with – brobert Oct 01 '19 at 17:06
  • Both should work, `_for` and `_with`, it won't be fixed just by changing that if you have other problems. The html content should be at `params[:post][:content]`. not `params[:content]`. – arieljuod Oct 01 '19 at 17:12
  • It now sends the param :content, but empty. Should I be seeing the updating of the value in realtime in the DOM with the js you provided? (it remains empty when I check) – brobert Oct 01 '19 at 17:46
  • It works!!! I need to update the content of the div at least once (so function(ev) is called) but it works!! thank you so much! – brobert Oct 01 '19 at 17:51
0

It looks like your form is refreshing the page before your submit handler is fired. You'll want to prevent this default behavior from happening, which you can do with the onsubmit event, like this:

    function getContent(event){
        event.preventDefault()
        document.getElementById("content").value = document.getElementById("post_content").innerHTML;
    }
Jay Kariesch
  • 1,392
  • 7
  • 13