0

I have a rails app with a custom pusher chat where chat message will be loaded by AJAX for the sender and by pusher socket for the receiver.

In my create.js.erb file I have duplicate code at the moment and I don't know what the best way is to wrapping a piece of code when it comes to js.erb template.

Could sby tell me, how to get rid of the duplication properly? The code before the broadcast function is the same code that is wrapped into the broadcast function.

create.js.erb

//first part is AJAX, only goes to sender
var id = "<%= @conversation.id %>";
var chatbox = $(".chatboxcontent");
var sender_id = "<%= @message.user.id %>";
var receiver_id = $('meta[name=user-id]').attr("content");

if (event.handled !== true) {

   $message = $('<%= j render @message %>');
   chatbox.append($message);
   chatbox.scrollTop(chatbox[0].scrollHeight);

   $(".chatboxtextarea").val("");
   $(".chatboxtextarea").focus();
   $(".chatboxtextarea").css('height', '44px');
   var timeField = ($message).find('.timefield');
   var nameField = ($message).find('#chatname');
   var createdAt = timeField.attr('datetime');
   var momentCreatedAt = moment(createdAt).format('hh:mm A');
   timeField.remove();
   $( "<span class='newtime'>" + " • " + momentCreatedAt + "</span>" ).insertAfter(nameField);

   if(sender_id != receiver_id) {
     chatbox.children().last().removeClass("self").addClass("other");
     chatbox.scrollTop(chatbox[0].scrollHeight);
   }
   event.handled = true;
}

//only broadcasted to receiver, sender is getting the message via the prev AJAX
<% broadcast_to_conversation(@conversation.id, @receiver_id) do %>
  var id = "<%= @conversation.id %>";
  var chatbox = $(".chatboxcontent");
  var sender_id = "<%= @message.user.id %>";
  var receiver_id = $('meta[name=user-id]').attr("content");

  if (event.handled !== true) {

    $message = $('<%= j render @message %>');
    chatbox.append($message);
    chatbox.scrollTop(chatbox[0].scrollHeight);

    $(".chatboxtextarea").val("");
    $(".chatboxtextarea").focus();
    $(".chatboxtextarea").css('height', '44px');
    var timeField = ($message).find('.timefield');
    var nameField = ($message).find('#chatname');
    var createdAt = timeField.attr('datetime');
    var momentCreatedAt = moment(createdAt).format('hh:mm A');
    timeField.remove();
    $( "<span class='newtime'>" + " • " + momentCreatedAt + "</span>" ).insertAfter(nameField);

    if(sender_id != receiver_id) {
        chatbox.children().last().removeClass("self").addClass("other");
        chatbox.scrollTop(chatbox[0].scrollHeight);
    }

    event.handled = true;
  }
<% end %>
3
  • You can create one function and put common code in that. Commented Feb 10, 2016 at 13:19
  • remove it to separate function in application.js Commented Feb 10, 2016 at 13:19
  • guys, could you provide code sample pls? I know I should put it into a function, just not sure how Commented Feb 10, 2016 at 13:43

1 Answer 1

2

1. Solution

You could create a partial and render it twice:

_chatbox.js.erb

var id = "<%= @conversation.id %>";
var sender_id = "<%= @message.user.id %>";
var receiver_id = $('meta[name=user-id]').attr("content");
var chatbox = $(".chatboxcontent");

if (event.handled !== true) {

  $message = $('<%= j render @message %>');
  chatbox.append($message);
  chatbox.scrollTop(chatbox[0].scrollHeight);

  $(".chatboxtextarea").val("");
  $(".chatboxtextarea").focus();
  $(".chatboxtextarea").css('height', '44px');
  var timeField = ($message).find('.timefield');
  var nameField = ($message).find('#chatname');
  var createdAt = timeField.attr('datetime');
  var momentCreatedAt = moment(createdAt).format('hh:mm A');
  timeField.remove();
  $( "<span class='newtime'>" + " • " + momentCreatedAt + "</span>" ).insertAfter(nameField);

  if(sender_id != receiver_id) {
    chatbox.children().last().removeClass("self").addClass("other");
    chatbox.scrollTop(chatbox[0].scrollHeight);
  }
  event.handled = true;
}

create.js.erb

<%= render "chatbox" %>

<% broadcast_to_conversation(@conversation.id, @receiver_id) do %>
  <%= render "chatbox" %>
<% end %>

2. Solution

But a better solution would be to extract the common code into one javascript function and parametrize this function with data you are getting from the controller. In this case you can better reuse your code from other parts of your application.

in your controller:

def create
  #...
  @chatbox_params = {id: @conversation.id, sender_id: @message.user.id}
  #...
end

application.js

function chatbox(params){
  var receiver_id = $('meta[name=user-id]').attr("content");
  var chatbox     = $(".chatboxcontent");

  if (event.handled !== true) {
    chatbox.append(params.message);
    chatbox.scrollTop(chatbox[0].scrollHeight);

    $(".chatboxtextarea").val("");
    $(".chatboxtextarea").focus();
    $(".chatboxtextarea").css('height', '44px');
    var timeField = (params.message).find('.timefield');
    var nameField = (params.message).find('#chatname');
    var createdAt = timeField.attr('datetime');
    var momentCreatedAt = moment(createdAt).format('hh:mm A');
    timeField.remove();
    $( "<span class='newtime'>" + " • " + momentCreatedAt + "</span>" ).insertAfter(nameField);

    if(params.sender_id != receiver_id) {
      chatbox.children().last().removeClass("self").addClass("other");
      chatbox.scrollTop(chatbox[0].scrollHeight);
    }
    event.handled = true;
  }
}

create.js.erb

var chatboxParams     = JSON.parse('<%= @chatbox_params.to_json %>');
chatboxParams.message = $('<%= j render @message %>');

chatbox(chatboxParams);

<% broadcast_to_conversation(@conversation.id, @receiver_id) do %>
  chatbox(chatboxParams);
<% end %>
Sign up to request clarification or add additional context in comments.

3 Comments

Dieter, nice solution! I see the idea behind putting the parameters into the controller, but why did you extract the message as chatboxParams.message?
I extracted all parameters which are variable in ruby(come from the controller). Other parameters don't depend on the server logic, they are just javascript statements. Of course you should better know how to design your API. It's just an example.
Dieter, for the guys who may find this post, could you update your answer and put the vars into the <% broadcast_to.... function as well? I guess chatParams won't be found otherwise, since the broadcast function will be invoked somewhere else.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.