cartjs icon indicating copy to clipboard operation
cartjs copied to clipboard

Automatically extracting data from form

Open bakura10 opened this issue 10 years ago • 8 comments

Hi,

When developing a theme, you cannot know in advance which properties a product have. As a consequence, this:

CartJS.addItem(12345678, 3, {
        "size": "XL"
    });

Is not possible because we cannot know that it will have the "size" property. The problem is that jQuery does not have any nice built-in function to extract the data from a form in a way that is easily consumed by CartJS. Here is the boilerplate code I've been doing:

var formData = this.serializeForm(this.element.find('.product__form'));
CartJS.addItem(formData['id'], formData['quantity'], formData['properties'], {});

where serializeForm is as follow:

Plugin.prototype.serializeForm = function(form) {
    var hash = {};

    function stringKey(key, value) {
      var beginBracket = key.lastIndexOf('[');
      if (beginBracket == -1) {
        var hash = {};
        hash[key] = value;
        return hash;
      }
      var newKey = key.substr(0, beginBracket),
        newValue = {};
      newValue[key.substring(beginBracket + 1, key.length - 1)] = value;

      return stringKey(newKey, newValue);
    }

    var els = form.find(':input').get();

    $.each(els, function() {
      if (this.name && !this.disabled && (this.checked || /select|textarea/i.test(this.nodeName) || /hidden|text|search|tel|url|email|password|datetime|date|month|week|time|datetime-local|number|range|color/i.test(this.type))) {
        var val = $(this).val();
        $.extend(true, hash, stringKey(this.name, val));
      }
    });

    return hash;
  },

I'm not the author of this complicated code, but basically, it allows to parse the keys (such as "properties[foo]") and returns something like:

{
   "id": 123,
   "quantity": 1,
   "properties": {
     "size": "XL",
     "other": "foo"
   }
}

This boilerplate code is required all the time in themes. Therefore, it would be nice to have a "addItemFromForm" method that would accept any jQuery object representing a form, and do this logic internally.

I'd be happy to contribute for that, I just want to be sure you don't have a better idea for that first ;).

Bye!

bakura10 avatar Sep 11 '15 07:09 bakura10

Is there any reason adding a data-cart-submit attribute to the form in question wouldn't work for this use case? (Docs).

gavinballard avatar Nov 24 '15 11:11 gavinballard

Actually I often need to do more than just submitting, like changing the button of the add to cart button, displaying "success" message... The data-cart-submit does not offer this flexibility.

bakura10 avatar Nov 24 '15 12:11 bakura10

Okay, fair enough. There is already the required logic inside the data-cart-submit functionality, I can look to pull it out and make it publicly accessible.

gavinballard avatar Nov 24 '15 12:11 gavinballard

@bakura10 I have a branch to resolve this: https://github.com/discolabs/cartjs/tree/36_form.

It will add two public methods:

/**
 * Expect a DOM form object.
 * Returns an array of [id, quantity, properties] extracted from the form.
  */
CartJS.extractItemFromForm(form) {
  ...
}
/**
 * Expect a DOM form object.
 * Uses extractItemFromForm() to attempt to parse an item to add from the form and then adds it.
  */
CartJS.addItemFromForm(form) {
  ...
}

Does this look like it would solve your use case?

gavinballard avatar Feb 03 '16 20:02 gavinballard

Perfect, that would solve it like a charm!

bakura10 avatar Feb 03 '16 20:02 bakura10

OK, great. I'll try to find some time to add tests and then merge.

gavinballard avatar Feb 03 '16 20:02 gavinballard

Any news about tagging this? :)

bakura10 avatar May 19 '16 16:05 bakura10

Unfortunately I haven't had much time to work on Cart.js of late. That'll hopefully change later in the year.

In the meantime, if this is something you really need, happy to look at any PR adding tests to the above branch.

gavinballard avatar May 20 '16 09:05 gavinballard