ruby-docx / docx

a ruby library/gem for interacting with .docx files
MIT License
431 stars 170 forks source link

How can we add a new table #152

Open suhasg opened 4 months ago

suhasg commented 4 months ago

Problem

I need to write a new table in an existing paragraph, and I don't see any functions supporting that. Please help.

eyupatis commented 3 months ago

First, you need to start with a template, which contains a 1x1 table on it and a single paragraph. You can create this template using Google Docs.

Than, you need to initialize the document object:

docx = Docx::Document.open("app/views/.../template.docx")

Than, you need to find the existing table on your template and duplicate it, it's rows and it's cells.

def add_docx_table(docx)
  # Note: Without this empty paragraph and not using insert_before
  # All tables are ending up at the bottom of the generated document
  add_docx_paragraph(docx, "")
  table = docx.tables.first.copy
  table.insert_before(docx.paragraphs.last)

  add_docx_table_headers(table, text)
  add_docx_table_rows(table, text)

  # Remove initial table artifacts that comes from the template
  table.rows.first.remove!
  table.rows.each do |row|
    row.cells.first.remove!
  end
end

def add_docx_paragraph(docx, text, prepend_new_line: false)
  add_docx_paragraph(docx, "") if prepend_new_line
  paragraph_copy = docx.paragraphs.first.copy
  paragraph_copy.text = text
  paragraph_copy.insert_after(docx.paragraphs.last)
end

def add_docx_table_headers(table, text)
  first_row = table.rows.first

  new_row = first_row.copy
  new_row.insert_after(first_row)
  first_cell = new_row.cells.first

  new_cell = first_cell.copy
  new_cell.insert_after(new_row.cells.last)
  new_cell.paragraphs.first.text = text
end

def add_docx_table_rows(table, text)
  first_row = table.rows.first

  new_row = first_row.copy
  new_row.insert_after(table.rows.last)
  first_cell = new_row.cells.first

  new_cell = first_cell.copy
  new_cell.insert_after(new_row.cells.last)
  new_cell.text = text
end

I modified my original code to be able to share this example, so it might have small problems here and there, but in order to understand the idea, I think it's a helpful example to start with.