What would be the best way to write this in JS / jQuery? (Several individual objects with several fields)

Warning: this is a long read, as there is a lot of information related to this problem, so prepare yourself and thank you for taking the time to go through this if you do!

I am currently writing a very large WebApp for a client and created many interactive applications for it, but I developed it and I decided: is there a standard way to do this, or maybe a better way ?

This is where I come to you guys to get an idea of โ€‹โ€‹whether there is a certain way to do this, as I am always looking to create optimal applications.

The task I had to complete

The application I create requires that the user can create an invoice for the products . This invoice can contain any number of products added to it through the search box. Each product is retrieved from the database and stored inside this search box, and each product can be added multiple times.

As the user adds the product, enter the product name in the search field and click the Add Product button. This adds the processed template to the product list. Pretty simple?

Problem

The big problem I ran into was that not only the account was able to contain a list of products , but each of these products contained various custom data . This meant that each product had several fields of its own that the user could edit, which changed a number of things. For example, one type of product has an amount that must be multiplied by the cost of the product in order to return the total price . Another product has a length , which must be multiplied by the width , which then must be multiplied by the cost of this product by the return of the total price.

As you can imagine, there are many different types of products with different fields with different calculations , which, at the end of creation, you need to analyze the PHP page , while maintaining complete variability, when the user can add / remove / edit products on the same account page -factures without leaping.

It was a nightmare for me, since I needed to have a way to keep it clean and have a bunch of different jQuery inputs / objects without colliding with each other anyway. I also had to differentiate the ones downloaded from the newly created products , as some of them might capture information from the database

The solution I built

Therefore, when a product is added to the list, the product contains several fields, the number of parts and a delete button. The first thing I did was make templates with replaceable tokens for each type of product. This was easy and excellent, and when the product was added to the list, I added the rel attribute (which I called "hook",) to each item associated with this product, so that I could add handlers that only modified elements with this particular hook .

For inputs, I used input arrays in the form <input name="Products[%HOOK%][%PRODUCTDATAKEY%]" value="%PRODUCTDATAVALUE%" /> . Where my main problem arose, I had to distinguish downloaded products that were already stored in the database from recently added products that had just been added. The way I did this was added [Loaded] in front of all arrays of input names, so my PHP script could deal with the [Loaded] array separately.

What is my concern?

My biggest problem is how randomly everything looked, from markup to code. Hooks fly everywhere, Very long input names , Several thousand lines of code and a headache of various keys and tokens that need to be replaced . It works great, it just feels awful when I look at it as a developer. Take this โ€œadded product,โ€ for example:

 <div class="item product special-order" rel="7" style=""> <input type="hidden" name="products[7][id]" value="17"> <input type="hidden" name="products[7][item_id]" value=""> <input type="hidden" name="products[7][type]" value="Special Order Flooring"> <input type="hidden" name="retail_price" class="invoice-base-cost" value="18.49"> <h4>Carpet Brand<a name="action" rel="7" class="btn btn-mini btn-danger remove-product initialized" style=""><i class="icon-remove"></i> Remove</a> </h4> <div class="item-details"> <div class="detail-column"> <div class="detail"> <span class="detail-label detail-label-medium"> Type:</span>Carpet </div> <div class="detail"> <span class="detail-label detail-label-medium">Range:</span> Carpet Brand </div> <div class="detail"> <span class="detail-label detail-label-medium"> Colour:</span><input required="" class="detail-input-large left-align" value="" type="text" name="products[7][colour]"> </div> <div class="detail"> <span class="detail-label detail-label-medium"> Length:</span><input type="text" name="products[7][length]" rel="7" class="length-field initialized" placeholder="Enter the length..." value="1.000"><span class="detail-unit">m</span> </div> </div> <div class="detail-column"> <div class="detail"> <span class="detail-label detail-label-large">Manufacturer:</span> <select class="detail-input-large" required="" name="products[7][manufacturer_id]"> <option value="14">Manufacturer 1</option> <option value="16">Manufacturer 2</option> </select> </div> <div class="detail"> <span class="detail-label detail-label-large">Width supplied:</span><input type="text" name="products[7][width]" class="width-field" value="5.000"><span class="detail-unit">m</span> </div> <div class="detail"> <span class="detail-label detail-label-large">Retail price per/m:</span> ยฃ18.49 </div> <div class="detail"> <span class="detail-label detail-label-large">Room:</span><input class="detail-input-large left-align" type="text" name="products[7][room]" value="" required="required"> </div> </div> <div class="item-cost"> <h5>Item cost</h5> ยฃ<span class="invoice-cost" rel="7">92.45</span> </div> </div> </div> 

Is it not overkill ? Can I not map them to JSON objects to make it much cleaner? Or is this the right way to do this?

This product had about 5 different event bindings , which was random due to the fact that if the length field was changed, the price had to be recalculated in width and the base price and only coincided with the width back , and all this was done with looking for fields with the same rel (hook) . This is just a mess for me. It would be great to get an expert opinion on how this was to be achieved.

+4
source share
3 answers

Second first two answers: use a framework designed to handle this.

Before you go, however, here is the first step to modulating your code: from what you described, you seem to have a list of .special-order elements, and each of these elements has its own life.

Try to reflect this in your markup and your code:

1- markup: use meaningful class names to identify elements that will have an active role (you already have: .special-order , .length-field , .remove-button ...). Make sure you have one node that wraps your entire html package (in your case: .special-order seems to play this role).

2 events: use these class names to bind your hooks:

 $('.remove-button').click(function(){ ... }); $('.length-field').change(function(){ ... }); 

3- If the list of your elements is dynamic (for example, you can add / remove elements through javascript without reloading the entire page), use event delegation to link your events:

 $('.special-order-list').on('click', '.remove-button', function(){ ... }); $('.special-order-list').on('change', '.length-field', function(){ ... }); 

4- Inside your handlers, follow the modularity presented in your markup. Two nodes are connected to each other if they are children of the same .special-order node. Thus, you can imagine a connection between nodes that does not depend on the explicit value of the "rel" field:

  $('.special-order-list').on('change', '.length-field', function(){ var $masterNode = $(this).closest('.special-order'); var basePrice = $masterNode.find('.base-price').val(); var length = $(this).val(); $masterNode.find('.total-price').val( basePrice * length ); }); 

5 Obviously, use functions if necessary:

  function recomputePrice($masterNode){ var basePrice = $masterNode.find('.base-price').val(); var length = $masterNode.find('.length-field').val(); $masterNode.find('.total-price').val( basePrice * length ); }); $('.special-order-list').on('change', '.length-field, .base-price', function(){ var $masterNode = $(this).closest('.special-order'); recomputePrice( $masterNode ); }); 

Organizing your page in modules and submodules (some of which will call them components or widgets ...) is considered "best practice" for page layout. It is a reference to SmaCSS , and it underlies several css / js frameworks such as Bootstrap or many others.

+3
source

As suggested by spez86; you must use the framework to create your own HTML code, as well as to bind events to the elements present in each section of HTML. I suggest you take a look at backbones and handlebarsjs . When you use these 2 in combination, you need to make minimal efforts to achieve your goal.
You can link to the URL to learn more about their use.
I will recommend that you work with the user interface first, i.e. create separate templates for your different type of product, and then on the "Add Product" button click the "Add" button to add a basic view to the product list container.
After you can successfully add HTML to the page, you can continue to bind the event to the child element present in the product template. This can be done inside the Backbone.View class events function. The event handler registered here attaches only to the elements present in this view, and not to any other element present on the DOM page that has the same CSS class. This way you get rid of the [rel] mechanism, as well as long input names. Hope this helps you a bit.

+3
source

Honestly, with the amount of data you are talking about and the number of ways to change it, you should look into a more robust structure and design to make data binding easier. There are many, but my personal favorite is AngularJS.

http://angularjs.org/

Start looking for this, as it can save you a lot of time developing the application, and then, of course, support it in the future.

+2
source

Source: https://habr.com/ru/post/1498577/


All Articles