I am brand new to Livewire/Jetstream and trying to make a little inventory application to try it out. In my example below I'm trying to show inventory items from DB on a table with the ability to update the inventory name and quantity from the table without going to an edit page.
I have a nested foreach and when I render the page the input fields in the loop show the value and then disappear but the value is showing correctly in the HTML. Any help would be appreciated!
**Show Inventory**
namespace App\Http\Livewire;
use App\Models\Inventory;
use Livewire\Component;
class ShowInventory extends Component
{
public $inventories;
public function mount()
{
$this->inventories = Inventory::orderBy('name')->get();
}
public function render()
{
return view('livewire.show-inventory');
}
public function name()
{
$this->name = $name;
}
public function update($id)
{
$data = $this->validate([
'name' => 'required',
'available_on_hand' => 'required',
]);
$this->item_id = $id;
$item = Inventory::find($this->item_id);
$item->update([
'name' => $this->name,
'available_on_hand' => $this->available_on_hand,
]);
}
}
**Show Item**
namespace App\Http\Livewire;
use App\Models\Inventory;
use Livewire\Component;
class ShowItem extends Component
{
public $inventory;
public function mount(Inventory $inventory)
{
$this->inventory = $inventory;
}
public function render()
{
return view('livewire.show-item');
}
}
**Parent Blade**
<table class="table-auto">
<thead>
<tr>
<th>Name</th>
<th>Quantity</th>
<th></th>
<th>View</th>
</tr>
</thead>
<tbody>
#foreach($inventories as $inventory)
#livewire('show-item', ['inventory' => $inventory], key($inventory->id))
#endforeach
</tbody>
</table>
**Nested Blade**
<form wire:submit.prevent="update({{ $inventory->id }})">
<tr>
<td><input type="input" wire:model="name" value="{{$inventory->name}}" /></td>
<td><input type="input" wire:model="available_on_hand" value="{{$inventory->available_on_hand}}" /></td>
<td><button type="submit">Save</button></td>
<td>View</td>
</tr>
</form>
<form wire:submit.prevent="update({{ $inventory->id }})">
<tr>
<td><input type="input" wire:model="name"/></td>
<td><input type="input" wire:model="available_on_hand"/></td>
<td><button type="submit">Save</button></td>
<td>View</td>
</tr>
</form>
in component
public $name, $available_on_hand;
//....
public function getModel($modelID)
{
$model = Inventory::find($modelID);
$this->name = $model->name;
$this->available_on_hand = $model->available_on_hand;
}
as you can see, always you call the getModel method, it bind to your properties the current values of model also you can edit them and save it.
You can't use both, value attribute and the wire:model, that give you the conflicts you have now
Related
I got this form
<div class="form-group">
<label for="clientId">Client</label>
<select name="client_id" class="form-control">
#if(count($client) == 0)
<option>There are no clients.</option>
#else
#foreach($client as $client)
<option value="{{$client->client_id}}">{{$client->client_name}}</option>
#endforeach
#endif
</select>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Submit</button>
</div>
Which sends the data to this controller
public function store(Request $r)
{
$validatedData = $r->validate([
'proj_title' => 'required|max:100',
'client_id' => 'required',
'proj_desc' => 'required',
]);
$currentUserId = Auth::user()->user_id;
$currentUser = User::find('username')->name;
$r['created_by'] = $currentUser;
$project = Project::create($r->all());
return redirect('/projects')->with('store','');
}
I have done a one-to-many relationship from Client to Project.
My intention is that you submit the client_id, inserts that into the db and then on the index you see the client_name relative to that client_id.
This is my index
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Project Id</th>
<th>Title</th>
<th>Description</th>
<th>Client</th>
<th>Created by</th>
<th>Created on</th>
#if (Auth::user()->role=='admin')
<th>Admin</th>
#endif
</tr>
</thead>
<tbody class="">
#foreach ($project as $project)
<tr>
<td>{{$project->proj_id}}</td>
<td>{{$project->proj_title}}</td>
<td>{{$project->proj_desc}}</td>
<td>{{$client->client_name}}</td>
<td>{{$project->created_by}}</td>
<td>{{$project->created_at}}</td>
These are my relations:
Project model:
class Project extends Model
{
protected $primaryKey = 'proj_id';
protected $fillable = ['proj_title','proj_desc','client_id','created_by'];
public function user()
{
return $this->hasOne('App\User');
}
public function task()
{
return $this->hasMany('App\Task');
}
public function client()
{
return $this->hasOne('App\Client');
}
}
Client:
class Client extends Model
{
protected $primaryKey = 'client_id';
protected $fillable= ['client_name','client_id'];
public function project()
{
return $this->hasOne('App\Project','proj_id');
}
}
As I have it right now I get "Property [client_name] does not exist on this collection instance. (View: D:\Programas\xampp\htdocs\test5\resources\views\projects\index.blade.php)"
Relations are still a bit confusing to me so sorry if this is a very noob question.
Thanks in advance
Client relation:
public function client()
{
return $this->belongsTo('App\Client');
}
Project relation:
public function projects()
{
return $this->hasMany('App\Project','proj_id');
}
And to get client name simply use $project->client->client_name, btw. use plural, learn writing code correctly...
my MessageController is as follows:
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
use App\Http\Requests;
use App\Message;
class MessageController extends Controller
{
public function CreateMessage(Request $request)
{
$meso = new Message();
$meso->body = $request['body'];
$meso->subject = $request['subject'];
$request->user()->messages()->save($meso) ;
return redirect()->route('mail');
}
public function getmailbox()
{
$message = Message::orderBy('created_at', 'desc')->get();
return view('dashboard', ['messages' => $message]);
}
}
and i am trying to retrieve the messages here in my mail.blade.php:
<table class="table table-inbox table-hover">
<tbody>
#foreach($messages as $message)
<tr class="unread">
<td class="inbox-small-cells">
<input type="checkbox" class="mail-checkbox">
</td>
<td class="inbox-small-cells"><i class="fa fa-star"></i></td>
<td class="view-message dont-show">Facebook</td>
<td class="view-message view-message"><p>{{ $message->body }}</p></td>
<td class="view-message inbox-small-cells"><i class="fa fa-paperclip"></i></td>
<td class="view-message text-right">feb 14</td>
</tr>
</tbody>
#endforeach
</table>
However this is the result i get from that query :
ErrorException in ed6d9659a06e690c67323133798cd26570bdc7a9.php line 200:
Undefined variable: messages (View: C:\xampp\htdocs\dating\resources\views\mail.blade.php)
Any help here
Laravel 5
Change the function structure :
public function CreateMessage(Request $request)
{
$meso = new Message();
$meso->body = $request['body'];
$meso->subject = $request['subject'];
$meso->save();
//$request->user()->messages()->save($meso) ;
/**
* You can get the last inserted ID
*
* If your message table having primaty key column name is id
*/
// $last_insert_id = $meso->id;
return redirect()->route('mail');
}
public function getmailbox()
{
$message = Message::orderBy('created_at', 'desc')->get();
return view('mail', ['messages' => $message]);
}
I am currently working on interface part a framework to generate HTML tags. Problem i am facing is while generating tags for nested tables and cells.
for this purpose, I have one html class which define common expectation of tags. Another class is htmlTable which is inherited from hrml class and customised for table, TR, TD. While i want to add nested tables on a particular cell, the result is unexpected. It generates hundreds of TDs and TRs.
Following code is customised to post here as putting all code will make long and too confusing.
And one more thing, I am only concentrated to solve logical error to get exact parent, child and nested elements of HTML tag.
I have tried as much as i could but couldnot get this fixed. This might be easy for some of you. So please advice me your solution. I have got to go to work so will reply only once i get back.
Thnak you
<?php
// scHTML.php
class HTML
{
protected $tag;
protected $id;
protected $values;
protected $childList;
protected $body;
public function __construct($tag,$id)
{
$this->tag=$tag;
$value= array('id'=>$id);
$this->setValues($value);
}
// to add nested tag
public function addChildTag(HTML $child)
{
$this->childList[]=$child;
}
// to add key and value on opening tag
public function setValues($values)
{
if(count($values)>0)
{
foreach($values as $key=>$value)
{
$this->values[$key]=$values;
}
}
}
// value inside tag
public function setBody($body)
{
$this->body=$body;
}
// generate HTML code
public function getHTML()
{
$return= '<'.$this->tag;
if(count($this->values)>0)
{
foreach($this->values as $key=>$value)
{
$return.=' '.$key.'= "'.$value.'" ';
}
}
$return.= '>
';
if(count($this->childList)>0)
{
$return.=
$this->body
;
foreach($this->childList as $child)
{
$return.=
$child->getHTML();
}
}
$return.=' </'.$this->tag.'>';
return $return;
}
public function __toString()
{
return $this->getHTML();
}
}
?>
and here is the inherited class for table
<?php
//scHTMLTable.php
include_once("scHTML.php");
class HTMLTable extends HTML
{
protected $cells; // logical grid of cells for current table
protected $row;
protected $column;
public function __construct($row,$column,$id)
{
$this->row=$row;
$this->column=$column;
$this->initiateTable();
$values['border']='1px';
$this->setValues($values);
parent::__construct("table",$id);
}
// initaite table cells according to row and column provided
private function initiateTable()
{
$td=new HTML("td",NULL);
$td->setBody(' ');
for($i=1;$i<=$this->row;$i++)
{
for($j=1;$j<=$this->column;$j++)
{
$this->addCell($i,$j,$td);
}
}
}
// set child element as body on a cell
public function addChildOnCell($row,$column,HTML $child)
{
$td=$this->cells[$row][$column];
$td->addChildTag($child);
$this->addCell($row,$column,$child);
}
// set cell
public function addCell($row,$column,HTML $cell)
{
$this->cells[$row][$column]=$cell;
}
// set TR as child and call parent method to generate html code.
public function getHTML()
{
for($i=1;$i<=$this->row;$i++)
{
$tr=new HTML("tr",NULL);
for($j=1;$j<=$this->column;$j++)
{
$td=$this->cells[$i][$j];
$tr->addChildTag($td);
}
$this->addChildTag($tr);
}
return parent::getHTML();
}
public function __toString()
{
return $this->getHTML();
}
}
?>
And here is the implementation.
<?php
include_once("scHTML.php");
include_once("scHTMLTable.php");
$html= new HTML("html",NULL);
$body=new HTML("body",NULL);
// three table to be tested
$a= new HTMLTable(3,3,"grandparent");
$b=new HTMLTable(3,3,"parent");
$c=new HTMLTable(1,1,"child");
$b->addChildOnCell(2,2,$c);
$a->addChildOnCell(2,2,$b);
$body->addChildTag($a);
$html->addChildTag($body);
echo $html;
?>
Output i am looking as source code is somewhere near this
<html>
<body>
<table border="1">
<tr>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td><table border="1">
<tr>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td><table border="1">
<tr>
<td> </td>
</tr>
</table></td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
</tr>
</table></td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
</tr>
</table>
</body>
</html>
I agree with MrMesees in that I think your table class is doing too much and that each node type is only responsible for generating it's own DOM representation. Any to-string / to-html recursion should only move downward through the DOM, though (no calls to parents for rendering assistance). Here is a quick demo using some of your custom API method names:
class HTML
{
private $tagName;
protected $attributes = [];
protected $children = [];
private $text = '';
public function __construct($tagName, $text='') {
$this->tagName = strtolower($tagName);
$this->text = $text;
}
public function addChildTag(HTML $n) {
$this->children[] = $n;
return $this;
}
public function getHTML($depth=0) {
$padding = str_repeat("\t", $depth);
$result = "$padding<$this->tagName";
foreach($this->attributes as $k => $v) {
$result .= " $k=\"".htmlspecialchars($v)."\"";
}
if (count($this->children) == 0 && strlen($this->text) == 0) {
$result .= " />\n";
}
else {
$result .= ">";
$result .= $this->text;
if (count($this->children) > 0) $result .= "\n";
foreach($this->children as $c) {
$result .= $c->getHTML($depth+1);
}
$result .= "$padding</$this->tagName>\n";
}
return $result;
}
public function tagName() { return $this->tagName; }
public function findChild($tagName, $index=0) {
$nodes = array_filter($this->children, function($e) use ($tagName) { return $e->tagName() == $tagName; });
return count($nodes) ? $nodes[$index] : null;
}
public function __toString() { return $this->getHTML(); }
}
class HTMLTable extends HTML {
public function __construct($rows, $cols, $id) {
parent::__construct("table");
$this->attributes['id'] = $id;
$this->attributes['border'] = '1px';
for($r=0; $r<$rows; $r++) {
$row = new HTML("tr");
for($c=0; $c<$cols; $c++) {
$cell = new HTML("td");
$row->addChildTag($cell);
}
$this->addChildTag($row);
}
}
public function addChildOnCell($row, $col, HTML $child) {
return $this->findChild("tr", $row-1)->findChild("td", $col-1)->addChildTag($child);
}
}
$html= new HTML("html");
$body=new HTML("body");
// three table to be tested
$a= new HTMLTable(3,3,"grandparent");
$b=new HTMLTable(3,3,"parent");
$c=new HTMLTable(1,1,"child");
$b->addChildOnCell(2,2,$c);
$a->addChildOnCell(2,2,$b);
$body->addChildTag($a);
$html->addChildTag($body);
echo $html;
Which results in output:
<html>
<body>
<table id="grandparent" border="1px">
<tr>
<td />
<td />
<td />
</tr>
<tr>
<td />
<td>
<table id="parent" border="1px">
<tr>
<td />
<td />
<td />
</tr>
<tr>
<td />
<td>
<table id="child" border="1px">
<tr>
<td />
</tr>
</table>
</td>
<td />
</tr>
<tr>
<td />
<td />
<td />
</tr>
</table>
</td>
<td />
</tr>
<tr>
<td />
<td />
<td />
</tr>
</table>
</body>
</html>
It's 2015, you should not be manually including files; there are clear coding-standards, so you should have namespaces and register an auto-loader in your main App.
Also as long as you are going to string build in this way, using the __toString() method on objects representing the tables, you should just have other classes for the nested parts, each with their own __toString method; so you can have HTMLElement class (you've got), with table (you have but it's not ideal), table-row, table-cell.
Extending this, you should if you take this route extend all HTMLElements, and have a rawString HTMLElement extended class for when you feel like just getting things done parrot fashion.
table row __toString method would just iterate over contained cells and return their __toString methods
table would iterate over rows and call their __toString method
table cell (the most / least difficult part), would take instances implementing HTMLElement, and iterate over them calling their __toString method
It's a lot cleaner method of working than the current, and then as each outputs it's own DOM, you should be free of the nasty bug you have now.
If the table gets too large, you are going to wish you had just coded a series of views that work with one-level of XYdata, or simplified in another way; but the data structures to this sort of nested view, unless you are working with JSON or XML anyway (in the case of XML, just use XSL); are not going to be nice to retrieve from say SQL Server, MySQL, search upon, or really to do that many useful things with...
I'm trying to learn codeigniter, the first thing i did is to make simple add edit delete function...
I'm having trouble calling the name of input button to the controller to delete an entire row of table..
model
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Delete_model extends CI_Model{
public function delete($data){
$this->db->delete('record_tbl', $data);
}
}
controller
class Delete_controller extends CI_Controller {
public function index()
{
$this->delete();
}
public function delete()
{
$data = array();
$this->load->model('fetch');
$query = $this->fetch->getData();
if ($query)
{
$data['results'] = $query;
}
$this->load->view('delete', $data);
}
public function delete_data(){
$this->load->model('delete_model');
$where = $this->input->get('id');
$data['id'] = $where;
$this->delete_model->delete($data);
redirect('');
}
}
view
<table border="1" width="100%">
<tr>
<th>Name</th>
<th>Address</th>
<th>Phone Number</th>
<th>Status</th>
<th></th>
</tr>
<?php foreach($results as $row) { ?>
<tr>
<td><?=$row->name?></td>
<td><?=$row->addr?></td>
<td><?=$row->pnum?></td>
<td><?=$row->status?></td>
<?php echo form_open('delete_controller/delete_data') ?>
<td style="text-align: center"><input name="<?=$row->id?>" type="submit" value="delete"></input>
</form>
</td>
</tr>
<?php } ?>
</table>
Your form will be doing a POST rather than a GET request. So rather than doing
$where = $this->input->get('id');
You want to do
$where = $this->input->post('id');
Also why don't you pass the value of $row->id to your controller so that you know which input field to target. So in your view do
<?php echo form_open('delete_controller/delete_data/' . $row->id) ?>
Then in your controller
public function delete_data($id){
$this->load->model('delete_model');
$where = $this->input->post($id);
//...
It's going to be $this->input->post ('id') like #Pattle says and you are using the "name" attribute of the form for the ID. What I usually do is use a hidden field (see form_hidden () helper in CI documentation) with the name "id" and the value you want ($row->id).
<?php echo form_hidden ('id', $row->id); ?>
Instead of $this->input->get('id'); use $this->input->post('id');.
And to simplify things up: I probably recommend using <button></button> as control buttons like delete functionality (it also works on edit/update FYI).
Coz you can just add attribute to a button value = $id and name=delete. And it would be like an <input type='submit'> just by adding an attribute of type='submit'
So
VIEW
<table border="1" width="100%">
<tr>
<th>Name</th>
<th>Address</th>
<th>Phone Number</th>
<th>Status</th>
<th></th>
</tr>
<?php foreach($results as $row) { ?>
<tr>
<td><?=$row->name?></td>
<td><?=$row->addr?></td>
<td><?=$row->pnum?></td>
<td><?=$row->status?></td>
<?php echo form_open('delete_controller/delete_data') ?>
<td style="text-align: center">
<?php
echo "<button type='submit' name='delete' value='" . $row->id . "'>" ;
echo "DELETE" ;
echo "</button>" ;
?>
</form>
</td>
</tr>
<?php } ?>
</table>
Then it would be very simple to fetch the id of the row you want to delete. Just do this in your controller $id = $_POST['delete']; or $id = $this->input->post('delete');
Adding products to my cart is working fine, but after adding product to cart its not able to view it in my view page without refreshing view page,
I tried redirect() method still no use.
How do i view my page after adding products to cart.
Any help??
my controller:
<?php
class Cart extends CI_Controller {
public function __construct() {
parent::__construct();
}
public function addtocart($cal_id, $f_id) {
if (empty($cal_id)) {
$this->load->view('Cart_view');
}
$this->load->model('cart_model');
$product = $this->cart_model->cart_contents($cal_id, $f_id);
foreach ($product as $row) {
$name = $row->title;
$fees = $row->fees;
}
$product = array(
'id' => $cal_id,
'qty' => 1,
'price' => $fees,
'name' => $name,
);
print_r($product);
$this->cart->insert($product);
$this->load->view('Cart_view');
}
public function destroy() {
$this->cart->destroy();
}
}
?>
my model:
<?php
class cart_model extends CI_Controller
{
public function __construct() {
parent::__construct();
}
public function cart_contents($cal_id,$f_id)
{
$product=$this->db->select('*')
->from('calander')
->join('fees','calander.cal_id=fees.cal_id')
->where('fees.cal_id',$cal_id)
->where('fees.f_id',$f_id)
->get();
return $product->result();
}
}
?>
my view
<html>
<head><title></title></head>
<body>
<?php
if ($cart = $this->cart->contents()) {
?><table>
<tr>
<td>
<h3><u>Cart page</u></h3>
</td>
</tr>
<tr>
<th>course</th>
<th>Quantity</th>
<th>Price</th>
</tr>
<?php
foreach ($cart as $contents) {
?><tr>
<td><?php echo $contents['name']; ?></td>
<td><input type="text" value="<?php echo $contents['qty']; ?>"></td>
<td><?php echo $contents['price']; ?></td>
</tr>
<?php } ?>
</table> <?php
// redirect(base_url('/index.php/Cart/Cart_view'));
}
?>
</body>
</html>
I dont understand what you are trying to do. When you load your view $this->load->view('Cart_view');, it is required to pass the data array, containing all the variables into the view like this $this->load->view('Cart_view',$data); . Without data array, view cannot display data. When ever you write code atleast, make variables names in such a way that other people will be able to understand what that variable stands for. Without enough data, i am taking the liberty of modifying your code
Controller
public function addtocart($cal_id, $f_id) {
$data=array(
'view'=>''
);
if (empty($cal_id)) {
$this->load->view('Cart_view',$data);
} else {
$this->load->model('cart_model');
$product = $this->cart_model->cart_contents($cal_id, $f_id);
$data['view']='';
foreach($product as $row):
$data['view'].=' <tr>
<td>'.$row->title.'</td>
<td>'.$row->qty.'</td>
<td>'.$row->price.'</td>
</tr>';
endforeach;
$this->load->view('Cart_view',$data);
}
}
MODEL
public function cart_contents($cal_id,$f_id){
$this->db->select('*')
$this->db->from('calander')
$this->db->join('fees','calander.cal_id=fees.cal_id')
$this->db->where('fees.cal_id',$cal_id)
$this->db->where('fees.f_id',$f_id);
$query = $this->db->get();
return $query->result();
}
view
<html>
<head><title></title></head>
<body>
<table>
<tr>
<td>
<h3><u>Cart page</u></h3>
</td>
</tr>
<tr>
<th>course</th>
<th>Quantity</th>
<th>Price</th>
</tr>
<?php if($count>0){
echo $view;
}?>
</table>
</body>
</html>