简体   繁体   中英

PHP foreach() outputs only the last item of an array

Sequel to my previous post, my intention was only to keep my question straight to the point and short, but obviously and for the sake of clarity, it's best I include all the modules involved.

I'm working on a CodeIgniter project that requires users to provide multiple options with the help of an input post array like the one shown in the view below:

<form action="javascript:void(0)" id="add_stock">
   <div class="stock">
      <div>
         <div class="form-group col-md-4">
           <input type="text" name="item[]" placeholder="Name of item" class="form-control item" id="item" />
           <span class="item_err"></span>
         </div>
         <div class="form-group col-md-4">
           <input type="text" name="unit[]" list="units" placeholder="Enter unit of measurement" class="form-control unit" id="unit" />
           <datalist id="units">
              <option>cube</option>
              <option>cup</option>
           </datalist>
           <span class="unit_err"></span>
         </div>
         <div class="form-group col-md-3">
            <input type="text" onfocus="(this.type='number')"  name="quantity[]" placeholder="Enter quantity" class="form-control quantity" id="quantity" />
            <span class="quantity_err"></span>
          </div>
          <div class="form-group col-md-1">
             <button class="btn btn-primary add-more-stock" title="Add more item" style ="height:33px;margin-top: ;"><i class="fa fa-plus"></i></button>
          </div>
          <div class="clearfix"></div>
       </div>
     </div>
     <div class="clearfix"></div>
     <div class="form-group msg"></div>
     <div class="form-group col-md-12">
       <button class="btn btn-primary add-stock text-uppercase"><i class="fa fa-plus"></i> add stock</button>
     </div>
 </form>

I have a jQuery code that appends additional input fields as shown below:

    var max_fields = 20; // maximun inputs allowed
    var items = $('.stock');
    var x = 1;
    $('.add-more-stock').click(function (e) {
      e.preventDefault();
      if (x < max_fields) {
        x++;
        $('.stock').append('<div><div class="form-group col-md-4"><input type="text" name="item[]" placeholder="Name of item" class="form-control item" id="item" /><span class="item_err"></span></div><div class="form-group col-md-4"><input type="text" name="unit[]" list="units" placeholder="Enter unit of measurement" class="form-control unit" id="unit" /><datalist id="units"><option>cube</option><option>cup</option><option>mudu</option><option>bags</option><option>carton</option> <option>crate</option> <option>bottle</option></datalist><span class="unit_err"></span></div><div class="form-group col-md-3"><input type="text" name="quantity[]" placeholder="Enter quantity" class="form-control quantity" id="quantity" /> <span class="quantity_err"></span></div><button class="btn btn-danger remove-stock col-sm-1" title="Remove item" style ="height:33px;margin-bottom: -1px; width: 40px;"><i class="fa fa-trash"></i></button></div>');
      }else{
        $('.input-alert').attr('class','alert alert-warning').html('<i class="fa fa-info-circle"></i> You have reached the maximun of 20 input fields reached.').show();
      }
    })

    
    $(items).on('click','.remove-stock',function (e) {
      e.preventDefault();
      $(this).parent('div').remove();
      $('.input-alert').hide();
    })

And here is the complete jQuery code that passes the contents of the text fields to my controller:

   $('.add-stock').click(function (e) {

      var item = new Array();
      var unit = new Array();
      var quantity = new Array();

      var item_arr = $("input[name^='item']");

      var unit_arr = $("input[name^='unit']");

      var quantity_arr = $("input[name^='quantity']");

      item_arr.each(function(){
        item.push(this.value);
      }); 

      unit_arr.each(function(){
        unit.push(this.value);
      }); 

      quantity_arr.each(function(){
        quantity.push(this.value);
      });

      $.ajax({
        url: '<?php echo base_url()?>admin/add_stock',
        type: 'post',
        data: {item:item,unit:unit,quantity:quantity},
        dataType: 'json',
        beforeSend: function () {
          $(".add-stock").html("<img src='<?php echo base_url()?>asset/images/a.gif' width='20' height='20'/> proceesing...");
        },
        success: function (data) {
          if (data.success) {
            $('.add-stock').html('<i class="fa fa-plus"></> add stock');
            $('.msg').attr('class', 'alert alert-success').html('<i class="fa fa-check"></> '+data.msg).delay(5000).fadeOut();
          }else if (data.error) {
            if (data.unit) {
              $('.add-stock').html('<i class="fa fa-plus"></> add stock');
              $('.unit_err').attr('class', 'text-danger').html(data.unit).delay(5000).fadeOut();
            }else if (data.item) {
              $('.add-stock').html('<i class="fa fa-plus"></> add stock');
              $('.item_err').attr('class', 'text-danger').html(data.item).delay(5000).fadeOut();
            }else if (data.quantity) {
              $('.add-stock').html('<i class="fa fa-plus"></> add stock');
              $('.quantity_err').attr('class', 'text-danger').html(data.quantity).delay(5000).fadeOut();
            }else if (data.failed) {
              $('.add-stock').html('<i class="fa fa-plus"></> add stock');
              $('.msg').attr('class', 'alert alert-danger').html('<i class="fa fa-times"></> could not procees request...').delay(5000).fadeOut();
            }
          }
        },
        error: function () {
          $('add-stock').html('<i class="fa fa-plus"></> add stock');
          $('.msg').attr('class', 'alert alert-warning').html('<i class="fa fa-warning"></> something went wrong.').delay(5000).fadeOut();
        }
      })
    })

So, am trying to get the options in order to store them in separate rows and respective columns with the help of PHP (CodeIgniter)...

So far, this is my full controller

    function add_stock()
    {
        
            $items = $_POST['item'];
            $units = $_POST['unit'];
            $quantitys = $_POST['quantity'];

            foreach ($items as $item) {
                $stock['item'] = $item;
            }

            foreach ($units as $unit) {
                $stock['unit_of_measurement'] = $unit;
            }

            foreach ($quantitys as $quantity) {
                $stock['quantity'] = $quantity;
            }
            $stock['added_by'] = 'Admin';
            
            
            $stmt = $this->db->insert('stocks', $stock);

            if($stmt):
                $array = array('success' => true, 'msg'=>'Item has been successfully added to store');
            else:
                $array = array('error' => true, 'failed'=>true);
            endif;
        echo json_encode($array);
    }

Now, the problem is that, instead of getting the whole contents of the array displayed, only the last content is outputted ie if the contents of $array are ['a','b'], instead of displaying a,b the foreach() loop only displays b.

But when I echo $items, $units or $quantitys itself, the contents of the array gets displayed.

So, please, how can I get all the contents of the array and insert them into different rows?

Thank you!

Your problem starts in your form, and then gets worse in your controller.

The specific issue in your controller is this:

foreach ($items as $item) {
   $stock['item'] = $item;
}

You're iterating over the $items array, but overwriting the value of $stock['item'] on each iteration. Only the last value is stored.

To fix this you need to do a number of things:

First, use array indexes in your form names. This allows you to extract the corresponding values in the arrays you receive in $_POST

In your HTML use name="item[0]" , name="unit[0]" , name="quantity[0]" in your <input> fields.

Then, in the Javascript code that adds new rows, increment the index for each new row. You already have a counter that you can use for this = x .

'<input type="text" name="item[' + x + ']" placeholder="Name of item" class="form-control item" id="item" />'

(I haven't reproduced the whole line - you get the idea)

These changes should give you three arrays in your input that you can iterate over in a single loop:

$items = $_POST['item'];
$units = $_POST['unit'];
$qtys = $_POST['quantity'];

for($i=0;$i<count($items); $i++) {
    $item = $items[$i];
    $unit = $units[$i];
    $qty = $qtys[$i];

    // Do your database update here with these three variables

}

Purists will note that you could use the array elements directly. I agree, but this is clearer.

You could extend the indexes to give you a two dimensional array:

name="products[0]['item']" 
name="products[0]['unit']"
name="products[0]['quantity']"

(and corresponding changes to use x in Javascript)

Then iterate over $_POST]['products']:

foreach($_POST['products'] as $product) {
     $unit = $product['unit'];
     ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM