3

I've been trying to solve this one for several days now and it's driving me nuts. I have some data that needs to be submitted by Ajax. It is dynamic, so I don't know how many fields it has. On top of that the names of the fields are multidimensional and also dynamic. For example one might have inputs with the name data[name] and data[title] whilst another larger one might have data[images][0][src], data[images][0][alt], data[images][0][description], data[images][1][src], data[images][1][alt], data[images][1][description] with an unknown number of elements to the array. My problem is that I need to get an object I can submit via Ajax whilst maintaining the structure of the data.

I've tried serialising the data, but that just comes up with a string of name = value. I've tried serialise array as well, but that just gives me an array of [name, value]. I've managed to generate the object manually using a regex to split it up, but I can't find a way to merge the resultant objects together. The latest version of my code is:

$('.modal-content').find('input[name^="data"]').each(function () {
    var found = $(this).attr('name').match(re).reverse();
    var temp = $(this).val();
    $.each(found, function ()
    {
        str = this.substr(1, this.length - 2);
        var t = {};
        t[str] = temp;
        temp = t;
    });
    data = $.each({}, data, temp);
});

Unfortunately it doesn't merge them, it overwrites what is in data with what is in temp. If data has data.images[0].src = "mysrc" and temp has data.images[0].alt = "myalt" then I just end up with data.images[0].alt = "myalt" and src is no longer there.

There has to be a simple way to do this, hell at this point I'd even take a complicated way to do this. Can someone please help me with this?

7
  • 1
    What does the HTML itself look like? It's dynamic, but does it follow a set pattern at all? Commented Nov 17, 2016 at 11:32
  • @RoryMcCrossan the only common factor is they're in a div with an ID and that they all follow the pattern name="data[x][y][z] where xyz are dynamic and there is an unknown number of segments. Some will be text inputs, others radio buttons, some selects and others text areas (I know that I'm only doing inputs atm, will adjust the code once working for inputs) Commented Nov 17, 2016 at 11:33
  • The actual HTML is quite lengthly so I've pasted a copy of the most complex version I have so far here - pasted.co/0643034a Commented Nov 17, 2016 at 11:37
  • What do you need the resulting JSON to look like? Commented Nov 17, 2016 at 11:37
  • Can't you make an array in which each position there is an object with the format {str: temp}? Commented Nov 17, 2016 at 11:38

2 Answers 2

2

Although there is already an accepted answer. Here are my 5 cents:

IMHO working with regex should be avoided when possible. So my suggestion would be to change the HTML a bit, adding some classes to the div that contain the image and change the name attribute of the inputs:

<li class="col-xs-12 col-sm-6 col-md-4 col-lg-3 gallery-image ui-sortable-handle">
        <div class="my-image">
            <img src="http://localhost:8000/img/example.jpg">
            <input type="hidden" name="src" value="img/example.jpg">
            <div class="form-group">
                <label for="title-0">Title:</label>
                <input type="text" name="title" class="form-control" id="title-0" value="Default Example Image 1" placeholder="Title">
            </div>
            <div class="form-group">
                <label for="description-0">Description:</label>
                <input type="text" name="description" class="form-control" id="description-0" value="A default example image." placeholder="Description">
            </div>
            <div class="form-group">
                <label for="alt-0">Alt tag (SEO):</label>
                <input type="text" name="alt" class="form-control" id="alt-0" value="fluid gallery example image" placeholder="Alt tag">
            </div>
            <div class="form-group">
                <label for="order-0">Order:</label>
                <input type="number" name="order" class="form-control image-order" id="order-0" value="0">
            </div>
            <button type="button" class="btn btn-danger remove-gallery-image-btn">× Delete</button>
        </div>
    </li>
    <li class="col-xs-12 col-sm-6 col-md-4 col-lg-3 gallery-image ui-sortable-handle">
        <div class="my-image">
            <img src="http://localhost:8000/img/example.jpg">
            <input type="hidden" name="src" value="img/example.jpg">
            <div class="form-group">
                <label for="title-1">Title:</label>
                <input type="text" name="title" class="form-control" id="title-1" value="Default Example Image 2" placeholder="Title">
            </div>
            <div class="form-group">
                <label for="description-1">Description:</label>
                <input type="text" name="description" class="form-control" id="description-1" value="A default example image." placeholder="Description">
            </div>
            <div class="form-group">
                <label for="alt-1">Alt tag (SEO):</label>
                <input type="text" name="alt" class="form-control" id="alt-1" value="fluid gallery example image" placeholder="Alt tag">
            </div>
            <div class="form-group">
                <label for="order-1">Order:</label>
                <input type="number" name="order" class="form-control image-order" id="order-1" value="1">
            </div>
            <button type="button" class="btn btn-danger remove-gallery-image-btn">× Delete</button>
        </div>
    </li>

Then build the object matching this class:

var obj = {
  data: {
    images: []
  }
}

var groups = $('.my-image');

groups.each(function(idx, el) {
  var child = {}
  $(el).find('input').each(function(jdx, info){
    var $info = $(info);
    child[$info.attr('name')] = $info.val();
  });

  obj.data.images.push(child);
});

We would have the same result, but it might be less error prone. Here is a plunker.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your input, but that's exactly what I don't want to do. Because the input is dynamic I'd have to write the code multiple times for each different type. I don't want to have to write one for images, one for videos, one for plain text, one for banners etc. With the regex it works with dynamic content, no matter what input fields I have as long as they start with data it just works.
1

You can loop all inputs with each() loop, create array from name attributes using split() and then use reduce to add to object

var result = {}

$('input').each(function() {
  var name = $(this).attr('name');
  var val = $(this).val();

  var ar = name.split(/\[(.*?)\]/gi).filter(e => e != '');

  ar.reduce(function(a, b, i) {
    return (i != (ar.length - 1)) ? a[b] || (a[b] = {}) : a[b] = val;
  }, result)

})

console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="gallery-images" class="ui-sortable">
  <li class="col-xs-12 col-sm-6 col-md-4 col-lg-3 gallery-image ui-sortable-handle">
    <div>
      <img src="http://localhost:8000/img/example.jpg">
      <input type="hidden" name="data[images][0][src]" value="img/example.jpg">
      <div class="form-group">
        <label for="title-0">Title:</label>
        <input type="text" name="data[images][0][title]" class="form-control" id="title-0" value="Default Example Image 1" placeholder="Title">
      </div>
      <div class="form-group">
        <label for="description-0">Description:</label>
        <input type="text" name="data[images][0][description]" class="form-control" id="description-0" value="A default example image." placeholder="Description">
      </div>
      <div class="form-group">
        <label for="alt-0">Alt tag (SEO):</label>
        <input type="text" name="data[images][0][alt]" class="form-control" id="alt-0" value="fluid gallery example image" placeholder="Alt tag">
      </div>
      <div class="form-group">
        <label for="order-0">Order:</label>
        <input type="number" name="data[images][0][order]" class="form-control image-order" id="order-0" value="0">
      </div>
      <button type="button" class="btn btn-danger remove-gallery-image-btn">× Delete</button>
    </div>
  </li>
  <li class="col-xs-12 col-sm-6 col-md-4 col-lg-3 gallery-image ui-sortable-handle">
    <div>
      <img src="http://localhost:8000/img/example.jpg">
      <input type="hidden" name="data[images][1][src]" value="img/example.jpg">
      <div class="form-group">
        <label for="title-1">Title:</label>
        <input type="text" name="data[images][1][title]" class="form-control" id="title-1" value="Default Example Image 2" placeholder="Title">
      </div>
      <div class="form-group">
        <label for="description-1">Description:</label>
        <input type="text" name="data[images][1][description]" class="form-control" id="description-1" value="A default example image." placeholder="Description">
      </div>
      <div class="form-group">
        <label for="alt-1">Alt tag (SEO):</label>
        <input type="text" name="data[images][1][alt]" class="form-control" id="alt-1" value="fluid gallery example image" placeholder="Alt tag">
      </div>
      <div class="form-group">
        <label for="order-1">Order:</label>
        <input type="number" name="data[images][1][order]" class="form-control image-order" id="order-1" value="1">
      </div>
      <button type="button" class="btn btn-danger remove-gallery-image-btn">× Delete</button>
    </div>
  </li>
  <li class="col-xs-12 col-sm-6 col-md-4 col-lg-3 gallery-image ui-sortable-handle">
    <div>
      <img src="http://localhost:8000/uploads/galleries\21\4-tux-30.jpg">
      <input type="hidden" name="data[images][2][src]" value="uploads/galleries\21\4-tux-30.jpg">
      <div class="form-group">
        <label for="title-2">Title:</label>
        <input type="text" name="data[images][2][title]" class="form-control" id="title-2" value="" placeholder="Title">
      </div>
      <div class="form-group">
        <label for="description-2">Description:</label>
        <input type="text" name="data[images][2][description]" class="form-control" id="description-2" value="" placeholder="Description">
      </div>
      <div class="form-group">
        <label for="alt-2">Alt tag (SEO):</label>
        <input type="text" name="data[images][2][alt]" class="form-control" id="alt-2" value="" placeholder="Alt tag">
      </div>
      <div class="form-group">
        <label for="order-2">Order:</label>
        <input type="number" name="data[images][2][order]" class="form-control image-order" id="order-2" value="2">
      </div>
      <button type="button" class="btn btn-danger remove-gallery-image-btn">× Delete</button>
    </div>
  </li>
  <li class="col-xs-12 col-sm-6 col-md-4 col-lg-3 gallery-image ui-sortable-handle">
    <div>
      <img src="http://localhost:8000/uploads/galleries\21\all-free-backgrounds-simple-style-darkblue-18.jpg">
      <input type="hidden" name="data[images][3][src]" value="uploads/galleries\21\all-free-backgrounds-simple-style-darkblue-18.jpg">
      <div class="form-group">
        <label for="title-3">Title:</label>
        <input type="text" name="data[images][3][title]" class="form-control" id="title-3" value="" placeholder="Title">
      </div>
      <div class="form-group">
        <label for="description-3">Description:</label>
        <input type="text" name="data[images][3][description]" class="form-control" id="description-3" value="" placeholder="Description">
      </div>
      <div class="form-group">
        <label for="alt-3">Alt tag (SEO):</label>
        <input type="text" name="data[images][3][alt]" class="form-control" id="alt-3" value="" placeholder="Alt tag">
      </div>
      <div class="form-group">
        <label for="order-3">Order:</label>
        <input type="number" name="data[images][3][order]" class="form-control image-order" id="order-3" value="3">
      </div>
      <button type="button" class="btn btn-danger remove-gallery-image-btn">× Delete</button>
    </div>
  </li>
</ul>

4 Comments

Thank you so much! It works! I'd not heard of reduce before. That's exactly what I needed.
You're welcome, you can read more about it here developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
I used arrow function on filter which is ES6 so if you need support for older browsers you can write it like this jsfiddle.net/Lg0wyt9u/1318
Thanks, I've updated my code so it works with older browsers too.

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.