HTML icon indicating copy to clipboard operation
HTML copied to clipboard

.textContent not working properly

Open patrickmaciel opened this issue 9 years ago • 15 comments

Hi.

I will try explain my problem, but please, forgive my terrible english.

First case

  • I have a table with 1 example line
  • When I click in some button I remove this line and then add a new one with the form data
  • After add a couple of lines I click in save button, send a POST and persist this data in the database
  • Everything works great

Second case (error)

  • Now I have some data in database, so I create the table without the example line and list all data from database in that table
  • When I click in the button for add a new data from the from the textContent not works: all the td is blank (but the input hidden in each td works great)

What I test?

I put some console.log/debug in my code and I notice when I get the tablet element, I get undefined instead of HTML object lib.

My code

HTML

    <!-- LINK TO ADD NEW ITEMS FROM FORM -->
    <div class="field">
      <a href="#" class="ui green button add-dynamic-table" data-table="#customer-team-table" data-field-form="customer_team" data-field-name="customerteam" data-message="#team-message">{!! trans('messages.btn.add') !!}</a>
    </div>

    <!-- THE TABLE -->
    <table class='ui table' id="customer-team-table">
      <thead>
        <tr>
          <th>{!! trans('messages.field.id') !!}</th>
          <th>{!! trans('messages.field.position_id') !!}</th>
          <th>{!! trans('messages.field.name') !!}</th>
          <th>{!! trans('messages.field.work_phone') !!}</th>
          <th>{!! trans('messages.field.mobile_phone') !!}</th>
          <th>{!! trans('messages.field.email') !!}</th>
          <th class='actions'>{!! trans('messages.field.actions') !!}</th>
        </tr>
      </thead>

      <tbody>
        @if (!empty($customer) and ($customer->customerTeam->count() > 0))
          @foreach ($customer->customerTeam as $team)
            <tr>
              <td>{!! $team->id !!}</td>
              <td>{!! $team->position->name !!}</td>
              <td>{!! $team->name !!}</td>
              <td>{!! $team->work_phone !!}</td>
              <td>{!! $team->mobile_phone !!}</td>
              <td>{!! $team->email !!}</td>
              <td class='actions'>
                <a class="ui icon mini button red destroy-modal" data-destroy-route='{!! URL::route("customerteams.destroy", $team->id) !!}'>
                  <i class="trash icon"></i>
                </a>
              </td>
            </tr>
          @endforeach
        @else
          <tr>
            <td colspan="7">{!! trans('messages.text.empty_table') !!}</td>
          </tr>
        @endif
      </tbody>
    </table>

Javascript

    $('.add-dynamic-table').click(function(event) {
      event.preventDefault();

      var name = undefined;
      var input_form = $(this).data('field-form');
      var input_name = $(this).data('field-name');
      var fields = HTML.query('.fields [name^="' + input_form + '"]');
      var table = HTML.query($(this).data('table'));

      // remove the example line when table is empty
      if ($($(this).data('table') + ' tbody tr td[colspan="7"]').length == 1) {
        $($(this).data('table') + ' tbody tr').remove();
      }

      // create a new TR
      var tr = table.query('tbody').add('tr');

      // create a new  TD inside this TR with just a "-" (not work)
      tr.add('td').textContent = '-';
      var id = $($(this).data('table')).find('tbody tr').length + 1;

      fields.each(function(field) {
        var $name = field.each('name').toString();
        $name = $name.match(/\[(.*?)\]/)[1];

        // create a new TD inside this TR
        var td = tr.add('td');

        // set the textContent based on tagName (not work)
        if ($(field).prop('tagName') == 'SELECT') {
          td.textContent = $(field).find('option:selected').text();
        } else if ($(field).prop('tagName') == 'INPUT') {
          td.textContent = field.each('value');
        }

        // add an input hidden inside this TD (works)
        var input = td.add('input[type="hidden"]');
        input.each('name', input_name + '[' + id + ']' + '[' + $name + ']');
        input.each('value', field.each('value'));
      });

      // add TD in this TR with a trash link button 
      var td = tr.add('td.actions');
      var a = td.add('a.ui.icon.mini.button.red.destroy-modal');
      a.add('i.icon.trash');
    });

If you need more informations, tell me please.

patrickmaciel avatar Jul 29 '15 14:07 patrickmaciel

I can solve this partially doing that:

tr.add('td{someValueHere');

But in my old code I need after that add an input inside this td, because that I need the td variable, otherwise I need to do...

tr.add('td{someValueHere').add('input......');

And that's much complicated in my case.


Backing to the problem:

Why using textContent( ) not work and using td{someValue} work?

patrickmaciel avatar Jul 29 '15 18:07 patrickmaciel

Why do you assume it is textContent that isn't working? Are you sure that the value(s) you are pulling out of the input or select elements are being returned as you expect?

In any case, the textContent property is not created/defined by HTML.js. It's just part of the DOM. So i doubt that is where the problem lies.

Also, if you want better help, i actually need a lot less information, not more. There is so much going on there in your mish-mash of jQuery and HTML.js code. I need a smaller example of the problem that i can run, if i'm going to be able to help. Or, failing that, put your whole example up somewhere public (like jsfiddle) so that i can see it in action, at least.

nbubna avatar Jul 30 '15 21:07 nbubna

What I know is:

When the table is empty, the same code works. When the table has some rows and I need to add a new one without remove the others, the code not works. It's the same code.

I solve that using the create tag and set value syntax - tag{value}.

Part of the code:

...
 var fields = HTML.query('.fields [name^="' + input_form + '"]');
...
fields.each(function(field) {
...    
  if ($(field).prop('tagName') == 'SELECT') {
    td.textContent = $(field).find('option:selected').text();
  } else if ($(field).prop('tagName') == 'INPUT') {
    td.textContent = field.each('value');
  }    
...
}

I identify what tag is and set the textContent of this new td.

I set a lot console.log in my code, and if I get this $(field).find('option:selected').text(); or field.each('value'); I get the correctly values, not null, empty or undefined.

But when the table has a few rows inside tbody and I do not remove them the problem occurs.

I don't really know how to explain it to you better, mainly because my English is not so good.

But overall this is the problem. I was four hours trying to figure out if it was my mistake, but have not found anything yet. So I decided the way I told you above. For the moment it is working.

I will try to simulate the same problem again, but now I am in doubt whether I continue using HTML.js or if I migrate everything to the 'DOMx`.

What do you advise?

patrickmaciel avatar Jul 31 '15 12:07 patrickmaciel

I'm glad you found a workaround. I still can't figure out the exact problem without having a runnable example. The code, despite its many quirky and inefficient parts, is not making it clear to me what's going wrong.

I would certainly consider switching to DOMx, but i can't say that will fix things, since i haven't identified the problem.

Why do you do field.each('value')? Are there times when field might be a list instead of a single element? It doesn't look that way in your code.

nbubna avatar Jul 31 '15 13:07 nbubna

Hmmmmm... maybe thats the problem. I notice when the textContent not work the td element created by HTML has an array element inside, something like this element[0] or array[0]. I do not remember.

I will try this tonight.

Thanks sir!

patrickmaciel avatar Jul 31 '15 17:07 patrickmaciel

Now I not understand... why field.each('value') return an array?

input value Array[1]
    0: "[email protected]"
    length: 1
    __proto__: Array[0]

patrickmaciel avatar Jul 31 '15 20:07 patrickmaciel

http://nbubna.github.io/HTML/#each(property)

That's the API. It's for getting properties from multiple items at once. If you have a single item and want a single value, you just use the property: field.value

nbubna avatar Jul 31 '15 21:07 nbubna

Still no work, and just in one location and for one table.

Thats my case:

1 - I fill the form

captura de tela 2015-08-01 21 17 53

2 - I press the button

3 - My script run and add a new line with blank text in all tds

captura de tela 2015-08-01 21 18 04

4 - In the console I can see each value inputed in form correctly, but texContent not work.

editar:596 tr [tr, tr]

editar:603 name ["customer_class_start[program_id]"]
editar:604 value 4
editar:605 text Programa Antes da Pré-escolaPrograma Estruturado de Baixo CustoPrograma Intensivão Meio-AnoPrograma Reforço EscolarPrograma de Alfabetização 2.0
editar:618 tagName SELECT
editar:620 select value Programa Intensivão Meio-Ano

editar:603 name ["customer_class_start[year]"]
editar:604 value 2013
editar:605 text 
editar:618 tagName INPUT
editar:624 input value 2013

editar:603 name ["customer_class_start[start_date]"]
editar:604 value 2013-01-01
editar:605 text 
editar:618 tagName INPUT
editar:624 input value 2013-01-01

editar:603 name ["customer_class_start[school_days]"]
editar:604 value 2012
editar:605 text 
editar:618 tagName INPUT
editar:624 input value 2012

editar:603 name ["customer_class_start[students]"]
editar:604 value 220
editar:605 text 
editar:618 tagName INPUT
editar:624 input value 220

The script still the same, but I change each('value') for just 'value' like you said.

...
 var fields = HTML.query('.fields [name^="' + input_form + '"]');
...
fields.each(function(field) {
...    
  if ($(field).prop('tagName') == 'SELECT') {
    td.textContent = $(field).find('option:selected').text();
  } else if ($(field).prop('tagName') == 'INPUT') {
    td.textContent = field.value;
  }    
...
}

I really don't know where is the problem.

patrickmaciel avatar Aug 02 '15 00:08 patrickmaciel

I convert my code to DOMx but get the following error (I'll post that in DOMx repository too).

Uncaught HierarchyRequestError: Failed to execute 'appendChild'
 on 'Node': Only one element on document allowed.

I get this error when I try to do that:

      var tr = table.query('tbody').append('tr');
      tr.append('td').textContent = '-';

      fields.each(function(field) {
        var td = tr.append('td');             // HERE I GET THE ERROR
      });

patrickmaciel avatar Aug 02 '15 01:08 patrickmaciel

I think I found something.

When I execute in Google Chrome console this code:

var table = document.query('#my-table-id');

I get undefined.

So I wait 2 seconds and execute the same code... and I get the table.

Why that delay?

patrickmaciel avatar Aug 02 '15 01:08 patrickmaciel

I figure out something:

  • I get the some table by id
  • then I append some tr and return that to a var called tr
  • the I create some tdand return the value of append to the var td
  • In the final... the table still the same..

So I try to append this new tr to a table: nothing happens.

Maybe the problem was that... how to use your lib manipulating each element separately and then join all together?


Sorry for my incredible english.

patrickmaciel avatar Aug 02 '15 02:08 patrickmaciel

This would be sooo much easier with a working example.

nbubna avatar Aug 03 '15 16:08 nbubna

The first post is a complete working example.

Anyway, I will try solve that.

Thanks for your time sir.

patrickmaciel avatar Aug 03 '15 17:08 patrickmaciel

The markup for the first post is embedded in some unspecified template language. It may be a working example for you. It is not for me. I would like to help you, but i have an incomplete picture of what is happening and limited time to spend combing through a large section of code.

nbubna avatar Aug 04 '15 16:08 nbubna

No problem my friend, I understand your point.

I will try write and functional* example for you tonight.

Thanks anyway.

patrickmaciel avatar Aug 04 '15 18:08 patrickmaciel