I'm working with ZF2 and Doctrine2, and created a form for a Place class. This Place has a Province property which I'd like to render as a Select field.
Everything works fine when I add new Places, but when I try to edit one, I don't know how to set the "selected" attribute to the correct Option in the Select field.
In the edit screen I get the following code:
...
<select name="lugar[localidad][provincia][select]">
<option value="">Seleccione provincia...</option>
<option value="1">Capital Federal</option>
<option value="2">Buenos Aires</option>
</select>
...
I would like to get the this instead (assuming the object being edit has Province=Buenos Aires):
...
<select name="lugar[localidad][provincia][select]">
<option value="">Seleccione provincia...</option>
<option value="1">Capital Federal</option>
<option value="2" selected>Buenos Aires</option>
</select>
...
This is the code of the fieldset which contains the ObjectSelect:
class LocalidadFieldSet extends Fieldset /*implements InputFilterAwareInterface*/
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('localidad');
$this->setHydrator(new DoctrineObject($objectManager))->setObject(new Localidad());
$provinciaFieldSet = new ProvinciaFieldSet($objectManager);
$this->add($provinciaFieldSet);
$this->add(array(
'name' => 'select',
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'options' => array(
'object_manager' => $objectManager,
'target_class' => 'Application\Entity\Localidad',
'property' => 'nombre',
'label' => 'Localidad',
'empty_option' => 'Seleccione localidad...'
)
));
}
}
This is where the previous FieldSet is included in his parent FieldSet:
$localidadFieldSet = new LocalidadFieldSet($objectManager);
$this->add($localidadFieldSet);
If my entity has the following properties:
$id
$name
I understand its corresponding FieldSet should only have a Select element, and when an object is bound, it should set the appropriate option as "selected". Am I right?
I got the name of the Select element wrong. I changed it from "select" to "id", and now it's setting the value properly.
Related
New to Laravel / Livewire.
I have a component that outputs a radio group, It renders fine.
When I select one of the radio controls I get an error, "Attempt to read property "id" on array"
Here I pass an array of options from my blade file
#livewire('test-options', ['options' => $option])
Component
class TestOptions extends Component {
public $selected;
public $options;
public function mount($options)
{
$this->options = $options;
}
public function render()
{
return view('livewire.test-options', [
'options' => $this->options
]);
}
component blade
<div>
#foreach($options['items'] as $option_items)
<div class="custom-control custom-radio">
<input
wire:model="selected"
class="custom-control-input"
type="radio"
id="rdio_{{$option_items['0']->id}}_{{$options['option']->id}}">
<label class="custom-control-label" for="rdio_{{$option_items['0']->id}}_{{$options['option']->id}}">{{$option_items['0']->title}}</label>
</div>
#endforeach
The issue is, when you select a radio, Livewire is refreshing the component. However, the $options array is not being passed again. mount() will only run when the component is first rendered.
You are already passing the options into the component, the $optons variable does not need to be mounted as it is already loaded and set here:
#livewire('test-options', ['options' => $option])
Change your code to:
class TestOptions extends Component {
public $selected;
public $options;
public function render()
{
return view('livewire.test-options', [
'options' => $this->options
]);
}
If you're also trying to get a value from the radio input, you'll need to add a value:
<input
wire:model="selected"
class="custom-control-input"
type="radio"
value="yourvaluehere"
id="rdio_{{$option_items['0']->id}}_{{$options['option']->id}}">
From the docs:
In Livewire components, you use mount() instead of a class constructor __construct() like you may be used to. NB: mount() is only ever called when the component is first mounted and will not be called again even when the component is refreshed or rerendered.
Read more here: Receiving Parameters
I want to set by default a value for select tag each time i click the button "Ajouter paiement" however when i add selected="selected" livewire does not recognize it.
how can i pass the value 1 to livewire each time i click the button by default?
here's the code:
<div class="form-group">
<select id="" class="form-control" wire:model="status_paiement.{{ $key }}" oninvalid="this.setCustomValidity('Ce champ est obligatoire')" onchange="this.setCustomValidity('')" required>
<option value="1" selected="selected">regler</option>
<option value="0" >encours</option>
</select>
#error('status_paiement.'.$value) {{ $message }}#enderror
</div>
</div>```
I have the same problem. I will try to explain what I did to solve this problem.
Separate your form to another livewire component
foreach($payments as $payment){
#livewire('payments.update-form',['payment' => $payment,'key'=>$payment['id']]) //pass a key to uniquely identify this component
}
<?php
namespace App\Http\Livewire\Payments;
use Livewire\Component;
class paymentsUpdateForm extends Component
{
public $payment= [];
public $status = 'pending';
public function mount($payment){
$this->payment= $payment; //This will set the current payment
$this->status = $payment['status']; //This will set the default status of the current payment
}
public function render()
{
return view('livewire.payments.update-form');
}
}
This is what livewire/payments/update-form looks like
...
<select wire:model="status">
<option value="1">regler</option>
<option value="0">encours</option>
</select>
...
Each iteration will create a new Laravel component with the given payments and key. Inside the mount function of the Laravel component, assigns payment using the given data from the parent component and set the default payment status on the current payment. Hope you understand my explanation and this will help you. Cheers!
Reading how validations work at https://laravel-livewire.com/docs/2.x/input-validation
I did not find if there is a way in livewire 2 when I have
validation error to hook event as I need to send dispatchBrowserEvent event
to show message with toastr ?
My form is rather big and val;idation field can be out of screen
and I want to pay attention of user that there are validation errors...
Updated Block # 1:
You propose to get rid of livewire validate method and use laravel validate methods, which are written here
https://laravel.com/docs/8.x/validation, like :
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
if ($validator->fails()) {
...
In my conmponent I define all variables under 1 variable $form :
public $form
= [
'name' => '',
'state_id' => '',
...
public function firstStepSubmit()
{
$rules = [
'name' => 'required',
'state_id' => 'required',
];
$validation = Validator::make( $this->form, $rules, Hostel::getValidationMessagesArray());
$failed = $validation->fails();
if ($failed) {
$errorMsg = $validation->getMessageBag();
$focus_field = array_key_first($errorMsg->getMessages());
$this->dispatchBrowserEvent('PersonalPageMessageWarning', [
'title' => 'Personal Hostel',
'message' => 'Your hostel has invalid data !',
'focus_field' => str_replace('form.', '', $focus_field ),
]);
$validation->validate(); // What for this line ? Looks like we really need it ?
return;
}
$this->currentStep = 2;
} // public function firstStepSubmit()
// What for is
$validation->validate();
line inside of failed block ? Do we really need it ?
2) moving to laravel original methods sems for me as step back... Are there some livewire hooks/methods for it ?
Thanks in advance!
I got a solution to that. Let's say you have next:
// in blade
<div class="col-md-6 flex-row">
<label for="name">Name</label>
<input id="name" type="text" class="form-control flex-row" wire:model="name">
#error('name') <span class="error" style="color: #ff0000">{{ $message }}</span> #enderror
</div>
<div class="col-md-6 flex-row">
<label for="last_name">Name</label>
<input id="last_name" type="text" class="form-control flex-row" wire:model="last_name">
#error('last_name') <span class="error" style="color: #ff0000">{{ $message }}</span> #enderror
</div>
.... // all the rest of elements
//in component
public $name, $last_name;
// the rest of properies
public function store()
{
$validation = Validator::make([
'name' => $this->name,
'last_name' => $this->last_name,
.....
], $this->rules());
if ($validation->fails()) {
$errorMsg = $validation->getMessageBag();
$this->dispatchBrowserEvent('focusErrorInput',['field' => array_key_first($errorMsg->getMessages())]);
$validation->validate();
}
//... other code
now, if validation fails, the above validation checks dispatch and event with all the non-validated fields and in the blade's script tag handle the element focus in order of the error bag field. So, if the element is out of windows this will be focused
<script>
window.addEventListener('focusErrorInput', event => {
var $field = '#' + event.detail.field;
$($field).focus()
})
</script>
I want to generate a select list using an Oracle query but instead of returning html for one select list with multiple options, my query generates multiple select lists with one option in each.
Here is what I want:
<select name="f01" style="width:200px;" id="typename">
<option value="" selected="selected">--Select--</option>
<option value="Apples">Apples</option>
<option value="Oranges">Oranges</option>
</select>
and here is what I am gettting:
<select name="f01" style="width:200px;" id="typename">
<option value="">--Select--</option>
<option value="Apples" selected="selected">Apples</option>
</select>
<select name="f01" style="width:200px;" id="typename">
<option value="">--Select--</option>
<option value="Oranges" selected="selected">Oranges</option>
</select>
Here is my query:
select APEX_ITEM.SELECT_LIST
(p_idx => 1
,p_value => TYPE_NAME
,p_attributes => 'style="width:200px;"'
,p_show_null => 'YES'
,p_null_value => NULL
,p_null_text => '--Select--'
,p_item_id => 'typename'
) "TYPE_NAME"
FROM ALL_TYPES;
What am I missing?
You're creating select for each row of your query.
Consider following:
select APEX_ITEM.SELECT_LIST_FROM_QUERY(
p_idx => 1,
p_query => 'SELECT TYPE_NAME from ALL_TYPES',
p_attributes => 'style="width:200px;"',
p_show_null => 'YES',
p_null_text => '--Select--',
p_item_id => 'typename')
from dual;
I'm having a difficult time autofocusing an input field with semantic-ui-react. The documentation doesn't seem to include an autoFocus prop and the focus prop doesn't place the cursor inside the input field as would be expected.
<Form onSubmit={this.handleFormSubmit}>
<Form.Field>
<Form.Input
onChange={e => this.setState({ username: e.target.value })}
placeholder='Enter your username'
fluid />
</Form.Field>
</Form>
EDIT: This code works:
<Form onSubmit={this.handleFormSubmit}>
<Form.Input
onChange={e => this.setState({ username: e.target.value })}
placeholder="Enter your username"
autoFocus
fluid />
</Form>
The focus prop is purely to add a focus effect on the input's appareance, it does not actually set the focus.
Any props unused by Semantic are passed down to the DOM element, so if you set an autoFocus prop, it should go down to the input.
However, as explained in the Form documentation:
Form.Input
Sugar for <Form.Field control={Input} />.
So your code should rather be:
const yourForm = (
<Form onSubmit={this.handleFormSubmit}>
<Form.Input
onChange={e => this.setState({ username: e.target.value })}
onSelect={() => this.setState({ usernameErr: false })}
placeholder="Enter your username"
error={usernameErr}
iconPosition="left"
name="username"
size="large"
icon="user"
fluid
autoFocus
/>
</Form>
)
Note that this only works if you want the focus to happen right when the wrapper component is mounted. If you want to focus the input after it has been mounted, you have to use a ref and call the focus() method on it, just as showed in the documentation, like so:
class InputExampleRefFocus extends Component {
handleRef = (c) => {
this.inputRef = c
}
focus = () => {
this.inputRef.focus()
}
render() {
return (
<div>
<Button content='focus' onClick={this.focus} />
<Input ref={this.handleRef} placeholder='Search...' />
</div>
)
}
}
Hope that helps!
I would have assumed that semantic UI would pass all unknown props to the root element, the input. So if it does, you should be able to add the autoFocus attribute to it, if not, you will have to control which input is being focused in your state.
<Input placeholder='Search...' focus={this.state.focusedElement === "search"}/>
In order to tell the input field to focus, you need to create a reference (ref) to the input field as follows:
import React, { useState, useRef } from 'react';
import { Input, Button } from 'semantic-ui-react';
const SearchInputExample = () => {
const [searchValue, setSearchValue] = useState('');
// Create reference to the input field
const searchRef = useRef(null);
const handleSearchValueChange = event => setSearchValue(event.target.value);
return (
<div>
<Input
placeholder="Search..."
// Assign the ref created to a ref attribute
ref={searchRef}
value={searchValue}
onChange={handleSearchValueChange}
/>
<Button
onClick={() => {
setSearchValue('');
// Use the ref assigned to put the focus inside the input
searchRef.current.focus();
}}
>
Clear search (and focus)
</Button>
</div>
);
};
export default SearchInputExample;
You can read more about the useRef() hook here