0

In my application there is a form which have a two select field , in which the last select is set to have a multiple selection. What I need is to insert the first pair of select field to be inserted as a single record into the database. When I try to do this using a for loop I am able to insert the record as a single row until and unless I select only one value for my 2nd select field. But If I select multiple fields for second select, the records isn't proper.

Also here user can add more divs by clicking ADD button

<div id="scope-brand-div">
    <div class="col-md-6">
        <div class="form-group">
            <label for="scope">Project Scope</label>
            <select name="scope[]" class="form-control scope-select">
                <option value=""></option>
                <option>A</option>
                <option>B</option>
                <option>C</option>
            </select>
        </div>
    </div>
    <div class="col-md-6">
        <div class="form-group">
            <label for="brands_used">Brands Used</label>
            <select multiple name="brands_used[]" class="form-control brand-select">
                <option value=""></option>
                <option>D</option>
                <option>E</option>
                <option>F</option>
            </select>
        </div>
    </div>
</div>

php

$s = $this->input->post('scope');
$b = $this->input->post('brands_used');

foreach( $s as $key => $n ) {
  $rows[] = $n.",".$b[$key];
}
print_r($rows);

SCENARIO 1

If I select single fields for both select, the output will be:

A, D
B, E

SCENARIO 2

If I select a multiple filed for the second select like A,(D,E) and B,F. Using the same loop above the result will be:

A, D
B, E

How can I insert the same fields If I select multiple fields for 2nd select field ad provided the user can add more divs same like this.

Edit 1

<div id="scope-brand-div">
                <div class="col-md-6">
                  <div class="form-group">
                    <label for="scope"><?php echo $this->lang->line('xin_project_scope');?></label>
                    <select name="scope[]" class="form-control select-border-color border-warning scope-select" data-plugin="select_hrm" data-placeholder="<?php echo $this->lang->line('xin_project_scope');?>">
                      <option value=""></option>
                      <?php foreach($all_project_scope as $scope) { ?>
                      <option value="<?php echo $scope->scope_name; ?>"><?php echo $scope->scope_name; ?></option>
                      <?php } ?>
                    </select>
                  </div>
                </div>
                <div class="col-md-6">
                  <div class="form-group brands-ajax">
                    <label for="brands_used"><?php echo $this->lang->line('xin_brands_used');?></label>
                    <select multiple name="brands_used[]" class="form-control select-border-color border-warning brand-select" data-plugin="select_hrm" data-placeholder="<?php echo $this->lang->line('xin_brands_used');?>">
                    <option value=""></option>
                      <?php foreach($all_brands as $brands) { ?>
                      <option value="<?php echo $brands->brand_name; ?>"><?php echo $brands->brand_name; ?></option>
                      <?php } ?>
                    </select>
                  </div>
                </div>
              </div>

<script type="text/javascript">
$(document).ready(function(){
    $('#add-new').click(function(){
    var invoice_items = '<div id="scope-brand-div">'
                        + '<div class="col-md-6">'
                        +'<div class="form-group">'
                        + '<label for="scope"><?php echo $this->lang->line('xin_project_scope');?></label>'
                        +'<select name="scope[]" class="form-control scope-select"  data-placeholder="<?php echo $this->lang->line('xin_project_scope');?>">'
                        +'<option value=""></option>'
                        <?php foreach($all_project_scope as $scope) { ?>
                        +'<option value="<?php echo $scope->scope_name; ?>"><?php echo $scope->scope_name; ?></option>'
                        <?php } ?>
                        + '</select>'
                        + '</div>'
                        + '</div>'
                        + '<div class="col-md-6">'
                        + '<div class="form-group brands-ajax">'
                        + '<label for="brands_used"><?php echo $this->lang->line('xin_brands_used');?></label>'
                        +'<select name="brands_used[]" class="form-control brand-select" data-placeholder="<?php echo $this->lang->line('xin_brands_used');?>">'
                        +'<option value=""></option>'
                        <?php foreach($all_brands as $brands) { ?>
                        +'<option value="<?php echo $brands->brand_name; ?>"><?php echo $brands->brand_name; ?></option>'
                        <?php } ?>
                        +'</select>'
                        +'</div>'
                        + '</div>'
                        +'</div>'
    $('#clone-parent').append(invoice_items).fadeIn(500);
});
});
</script>

<?php
    public function add_project() {
    $s = $this->input->post('scope');
    $b = $this->input->post('brands_used');
    foreach( $s as $key => $n ) {
       $rows[] = $n.",".$b[$key];
        //insert query
      }
}

?>

Edit 2

echo var_export($this->input->post('brands_used'));

array (
0 => 
 array (
   0 => 'Opterna',
   ),
1 => 
 array (
    0 => 'Norden',
    ),
2 => 'Opterna',
)

echo var_export($this->input->post('scope'));

array (
 0 => 'ACS',
 1 => 'SMA TV',
 )
Aishwaryas
  • 633
  • 2
  • 18
  • 44
  • can you post your full code – skWyz Feb 01 '20 at 08:21
  • Please see my edit.I have added the code. – Aishwaryas Feb 01 '20 at 08:46
  • I _think_ you are considering making a deeper `$_POST` array structure so that you can keep groups of data separated. Think in terms of `scope[][]`. I'm thinking you need a counter variable to declare the first level grouping index -- otherwise auto incrementing will not be as desired. This is just a guess/hint -- not an answer. – mickmackusa Feb 01 '20 at 09:37
  • `` can be safely reduced to `` – mickmackusa Feb 01 '20 at 09:44
  • Wait s sec... if the `scope` field is not `multiple`, then it should not be named as `scope[]`. Also `for` only relates to a field's `id` attribute. Once you want to have a dynamic number of `scope` fields, then `scope[]` or `scope[i]` becomes appropriate (no need for `scope[][]`). `brands_used` should become `brands_used[][]` or `$brands_used[i][]` so that related data remains related. – mickmackusa Feb 01 '20 at 10:18
  • We have to use `scope[]` even its not multiple because the user can duplicate those divs. I was also trying to replace `brands_used[]` to `brands_used[][]`. Any idea how we can traverse through it? – Aishwaryas Feb 01 '20 at 10:41
  • `echo "
    "; var_export($this->input->post());` this will clarify the input data for me and other volunteers. @Ais edit this information into your question.
    – mickmackusa Feb 01 '20 at 11:36
  • 1
    Added to my edit @mick – Aishwaryas Feb 01 '20 at 11:54
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/207018/discussion-between-aishwaryas-and-mickmackusa). – Aishwaryas Feb 01 '20 at 11:55

1 Answers1

0

About your html...

  • the for in your label only works properly if associated with the id attribute of your field.
  • <option> tags which have identical values in the text and in the value attribute can have their value attribute removed entirely -- it works exactly the same at submission time but removes bloat from your html.
  • I am appending a counter to the id and the clonable class to your outermost <div> to aid the javascript cloning process.
  • brands_used[][] needs to be brands_used[0][] to prevent unwanted incrementation of the first level index.

Rewrite:

<div id="scope-brand-div0" class="clonable">
    <div class="col-md-6">
        <div class="form-group">
            <label for="scope0"><?php echo $this->lang->line('xin_project_scope'); ?></label>
            <select id="scope0" name="scope[]" class="form-control select-border-color border-warning scope-select" data-plugin="select_hrm" data-placeholder="<?php echo $this->lang->line('xin_project_scope'); ?>">
                <option></option>
                <?php foreach ($all_project_scope as $scope) {
                    echo "<option>{$scope->scope_name}</option>";
                } ?>
            </select>
        </div>
    </div>
    <div class="col-md-6">
        <div class="form-group brands-ajax">
            <label for="brands_used0"><?php echo $this->lang->line('xin_brands_used'); ?></label>
            <select multiple id="brands_used0" name="brands_used[0][]" class="form-control select-border-color border-warning brand-select" data-plugin="select_hrm" data-placeholder="<?php echo $this->lang->line('xin_brands_used'); ?>">
                <option></option>
                <?php foreach ($all_brands as $brands) {
                    echo "<option>{$brands->brand_name}</option>";
                } ?>
            </select>
        </div>
    </div>
</div>

As for your cloning javascript... I advise that you use clone() to clean up your script. Perhaps draw some inspiration from https://stackoverflow.com/a/8018242/2943403.

You will need to ensure that a "counter" is implemented. The original/hardcoded set of fields will have 0 as the counter; all additional sets of fields should replace all 0 values with the next incremental integer. This will keep all related fields in their related groups at submission time.

Specifically:

  • <div id="scope-brand-div0"> (if you actually need it) will become <div id="scope-brand-div1">
  • <label for="scope0"> will become <label for="scope1">
  • <select id="scope0"> will become <select id="scope1">
  • <label for="brands_used0"> will become <label for="brands_used1">
  • <select multiple id="brands_used0" name="brands_used[0][]" will become <select multiple id="brands_used1" name="brands_used[1][]"

The, of course, if the Add button is clicked a second time, all of the 1's need to become 2's.


As for processing your $_POST data, I expect to receive a structure like this: (don't stop tweaking your form until it delivers this most-appropriate structure)

$_POST = [
    'scope' => [
        'ACS',
        'SMA TV'
     ],
     'brands_used' => [
         [
             'Opterna',
             'Norden'
         ],
         [
             'Opterna'
         ]
     ]
];

This means you can use the same first level keys to access related scope and brands_used values. As you traverse the data, scope data will be a string and brands_used will be an array.

To iterate:

// make an object-oriented mysqli connection ($mysqli)
$stmt = $mysqli->prepare("INSERT INTO tablensme (scope, brand_used) VALUES (?, ?)");
$stmt->bind_param('ss', $scope, $brand_used);
$posted = $this->input->post();
foreach ($posted['scope'] as $index => $scope) {
    // use $scope string
    foreach ($posted['brands_used'][$index] as $brand_used) {
        // use $brand_used string
        $stmt->execute();
    }
}

Assuming you have a normalized db table structure and want to write one scope value and one brand_used value per table row, set up your prepared statement and bound variables prior to the loop, then call execute() from the inner loop.

This is 100% NOT TESTED, but the intended result from inserting the sample data would be the following new rows:

('ACS', 'Opterna'),
('ACS', 'Norden'),
('SMA TV', 'Opterna')
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • This is best that I can do from my phone and your provided details. If this doesn't work as desired, I'll try to adjust my answer, but you will need to be very clear about how my answer is failing and provide any client-side or server-side error messages. – mickmackusa Feb 01 '20 at 14:04
  • Before testing my code, I created the same scenario in a raw file just to get the POST structure as you mentioned. array ( 0 => array ( 0 => 'Opterna', 1 => 'Opterna', 2 => 'Opterna', 3 => 'Norden', ), ) this is my result of `$_POST['brands_used']`. I have changed `brands_used[]` to `brands_used[0][]` – Aishwaryas Feb 02 '20 at 06:52
  • The `[0]` must be incremented each time the foelds are cloned -- this maintains the grouping. This is what js block is intending to do. – mickmackusa Feb 02 '20 at 07:25