php - formularios - propiedades checkbox html
Genere HTML para mostrar preguntas personalizadas con el tipo correcto(texto, casilla de verificación,...) y agregue el atributo requerido correctamente (3)
Tengo un formulario para que un usuario cree preguntas personalizadas. Para eso, el usuario debe introducir la pregunta (por ejemplo: ¿Cuál es su teléfono?) Y también el tipo de campo (texto, texto largo, casilla de verificación, menú de selección, botón de opción). Si el usuario selecciona un campo de casilla de verificación, seleccione el menú o el botón de opción, también deberá introducir las opciones disponibles para la pregunta.
En la base de datos, las preguntas se insertan en las tablas de preguntas y preguntas como:
Tabla de preguntas:
id question type conference_id
1 Text text 1
2 Checkbox checkbox 1
3 Radio radio_btn 1
4 select select_menu 1
5 textarea long_text 1
6 file file 1
Tabla de pivote de Registration_type_questions
id registration_type_id question_id required
1 1 1 1
2 1 2 1
3 1 3 0
4 1 4 0
5 1 5 0
6 1 6 1
Las opciones se almacenan en la tabla questions_options:
id question_id value
1 2 check1
2 2 check2
3 3 rad1
4 3 rad2
5 4 select1
6 4 select2
Luego, en la vista, quiero mostrar correctamente en la vista registration.blade.php las entradas (texto, botón de opción, casilla de verificación, selección, área de texto y archivo de entrada) según el tipo almacenado en la columna "tipo" de la tabla de preguntas. Y también agregue el atributo requerido si la columna requerida en la tabla dinámica es "1".
Cuando una pregunta es del tipo texto, botón de opción, selección, área de texto o archivo funciona bien, el atributo requerido se agrega al campo de formulario.
Pero no funciona correctamente con las casillas de verificación porque, en el caso de las casillas de verificación, si la pregunta es de tipo casilla de verificación y la pregunta es necesaria, debe significar que el usuario debe responder a esa pregunta, pero no debe significar que debe marcar todas las casillas de verificación.
El problema es que con la función getHTMLInput () el html generado para las casillas de verificación se ha requerido en cada entrada de casilla de verificación y, debido a eso, el usuario debe marcar todas las casillas de verificación:
<div class="form-group">
<label for="participant_question">Checkbox</label>
<div class="form-check">
<input type="checkbox" name="participant_question[]" value="check1" class="form-check-input" required="">
<label class="form-check-label" for="exampleCheck1">check1</label>
</div>
<div class="form-check">
<input type="checkbox" name="participant_question[]" value="check2" class="form-check-input" required="">
<label class="form-check-label" for="exampleCheck1">check2</label>
</div>
<input type="hidden" name="participant_question_required[]" value="1">
<input type="hidden" value="2" name="participant_question_id[]">
</div>
¿Sabes cómo resolver ese problema? Cuando se requiere una pregunta personalizada, eso significa que la pregunta es necesaria, por lo que el usuario debe seleccionar al menos 1 casilla de verificación pero no debe significar que el usuario debe marcar todas las casillas de verificación.
Y también sabe cómo hacerlo, si se requiere la pregunta personalizada, agregue dentro de cada etiqueta de pregunta " <span class="text-primary">*</span>
"?
GetHtmlInput () en el modelo de pregunta:
class Question extends Model
{
protected $fillable = [
''question'', ''type'', ''conference_id'',
];
public static $typeHasOptions = [
''radio_btn'',
''select_menu'',
''checkbox''
];
public function registration_type()
{
return $this->belongsToMany(''App/RegistrationType'', ''registration_type_questions'')
->withPivot(''required'');
}
public function options()
{
return $this->hasMany(''App/QuestionOption'');
}
public function hasOptions()
{
return in_array($this->type, self::$typeHasOptions);
}
public function getHtmlInput($name = "", $options = "", $required = false, $class = "", $customtype = false) {
$html = '''';
$html .= $customtype == ''select_menu'' ? "<select name=''participant_question'' class=''form-control'' " . ($required ? " required" : "")
. ">" : '''';
if (empty($options)) {
switch ($customtype) {
case "text":
$html .= "
<input type=''text'' name=''participant_question'' class=''form-control''" . ($required ? " required" : "")
. ">";
break;
case "file":
$html .= "
<input type=''file'' name=''participant_question'' class=''form-control''" . ($required ? " required" : "") . ">";
break;
case "long_text":
$html .= "
<textarea name=''participant_question'' class=''form-control'' rows=''3''" . ($required ? " required" : "") . ">"
. $name .
"</textarea>";
break;
}
} else {
foreach ($options as $option) {
switch ($customtype) {
case "checkbox":
$html .= "
<div class=''form-check''>
<input type=''checkbox'' name=''participant_question[]'' value=''" . $option->value . "'' class=''form-check-input''" . ($required ? " required" : "") . ">" .
'' <label class="form-check-label" for="exampleCheck1">'' . $option->value . ''</label>'' .
"</div>";
break;
case "radio_btn":
$html .= "
<div class=''form-check''>
<input type=''radio'' name=''participant_question[]'' value=''" . $option->value . "'' class=''form-check-input''" . ($required ? " required" : "") . ">" .
'' <label class="form-check-label" for="exampleCheck1">'' . $option->value . ''</label>'' .
"</div>";
break;
case "select_menu":
$html .= "<option value=''" . $option->value . "''>" . $option->value . "</option>";
break;
}
}
}
$html .= $customtype == ''select_menu'' ? "</select>" : '''';
return $html;
}
}
Entonces el getHtmlInput () se usa como:
@if ($allParticipants == 0)
@foreach($selectedRtype[''questions''] as $customQuestion)
<div class="form-group">
<label for="participant_question">{{$customQuestion->question}}</label>
@if($customQuestion->hasOptions() && in_array($customQuestion->type, [''checkbox'', ''radio_btn'', ''select_menu'']))
{!! $customQuestion->getHtmlInput(
$customQuestion->name,
$customQuestion->options,
($customQuestion->pivot->required == ''1''),
''form-control'',
$customQuestion->type)
!!}
@else
{!! $customQuestion->getHtmlInput(
$customQuestion->name,
[],
($customQuestion->pivot->required == ''1''),
''form-control'',
$customQuestion->type)
!!}
@endif
<input type="hidden"
name="participant_question_required[]"
value="{{ $customQuestion->pivot->required }}">
<input type="hidden"
value="{{ $customQuestion->id }}"
name="participant_question_id[]"/>
</div>
@endforeach
@endif
HTML generado con getHTMLInput ():
<form method="post" action="">
<div class="form-group">
<label for="participant_question">Text</label>
<input type="text" name="participant_question" class="form-control" required="">
<input type="hidden" name="participant_question_required[]" value="1">
<input type="hidden" value="1" name="participant_question_id[]">
</div>
<div class="form-group">
<label for="participant_question">Checkbox</label>
<div class="form-check">
<input type="checkbox" name="participant_question[]" value="check1" class="form-check-input" required="">
<label class="form-check-label" for="exampleCheck1">check1</label>
</div>
<div class="form-check">
<input type="checkbox" name="participant_question[]" value="check2" class="form-check-input" required="">
<label class="form-check-label" for="exampleCheck1">check2</label>
</div>
<input type="hidden" name="participant_question_required[]" value="1">
<input type="hidden" value="2" name="participant_question_id[]">
</div>
<div class="form-group">
<label for="participant_question">Radio</label>
<div class="form-check">
<input type="radio" name="participant_question[]" value="rad1" class="form-check-input">
<label class="form-check-label" for="exampleCheck1">rad1</label>
</div>
<div class="form-check">
<input type="radio" name="participant_question[]" value="rad2" class="form-check-input">
<label class="form-check-label" for="exampleCheck1">rad2</label>
</div>
<input type="hidden" name="participant_question_required[]" value="0">
<input type="hidden" value="3" name="participant_question_id[]">
</div>
<div class="form-group">
<label for="participant_question">select</label>
<select name="participant_question" class="form-control">
<option value="select1">select1</option>
<option value="select2">select2</option>
</select>
<input type="hidden" name="participant_question_required[]" value="0">
<input type="hidden" value="4" name="participant_question_id[]">
</div>
<div class="form-group">
<label for="participant_question">textarea</label>
<textarea name="participant_question" class="form-control" rows="3"></textarea>
<input type="hidden" name="participant_question_required[]" value="0">
<input type="hidden" value="5" name="participant_question_id[]">
</div>
<div class="form-group">
<label for="participant_question">file</label>
<input type="file" name="participant_question" class="form-control" required="">
<input type="hidden" name="participant_question_required[]" value="1">
<input type="hidden" value="6" name="participant_question_id[]">
</div>
<input type="submit" class="btn btn-primary" value="Store">
</form>
Además, al verificar este formulario en un validador de HTML como el validador w3c, aparecen algunos errores:
- El atributo for del elemento label debe referirse a un control de formulario no oculto. En el texto
- El atributo for del elemento label debe referirse a un control de formulario no oculto. En "Checkb"
- El atributo for del elemento label debe referirse a un control de formulario no oculto. En "check1"
- El atributo for del elemento label debe referirse a un control de formulario no oculto. En "check2"
- El atributo for del elemento label debe referirse a un control de formulario no oculto. En "rad1
- El atributo for del elemento label debe referirse a un control de formulario no oculto. En "rad2
- El atributo for del elemento label debe referirse a un control de formulario no oculto. En "seleccionar"
- El atributo for del elemento label debe referirse a un control de formulario no oculto. En "textar"
- El atributo for del elemento label debe referirse a un control de formulario no oculto. En archivo
Esto se debe a que tiene el cuadro de verificación html dentro de su bucle foreach
aquí:
foreach ($options as $option) {
switch ($customtype) {
case "checkbox":
$html .= "
<div class=''checkbox-group'' " . ($required ? " required" : "") . ">
Debe pensar en cómo resolvería esto, tal vez usando una variable como $checkboxesFound
y establézcala en 0 al inicio de la función y cuando el caso es checkbox, incremente la variable, y si $checkboxesFound == 0
entonces haga eco en el grupo div.
HTML5 no tiene una solución para implementar que se requiera un grupo de casillas de verificación, por lo que con algunos cambios podría lograrlo. Primero, en su controlador, tendrá que cambiarlo para lograr lo mismo que está haciendo con su menú de selección.
// on top of your method:
$html .= $customtype == ''checkbox'' ? "<div class=''checkbox-group ".($required ? " required" : "")."''>" : '''';
// at the bottom
$html .= $customtype == ''checkbox'' ? "</div>" : '''';
Luego, en la casilla de verificación de su caso, solo tendría que imprimir las opciones que estarán dentro de su ''grupo de casillas de verificación requeridas'':
case "checkbox":
$html .= "
<div class=''form-check''>
<input type=''checkbox'' name=''participant_question[]'' value=''" . $option->value . "'' class=''form-check-input'' ><label class=''form-check-label'' for=''exampleCheck1''>" . $option->value . "</label>
</div>";
Esto debería generar el siguiente html:
<div class="checkbox-group required">
<div class="form-check">
<input type="checkbox" name="participant_question[]" value="whatever" class="form-check-input"><label class="form-check-label" for="exampleCheck1">whatever</label>
</div>
<div class="form-check">
<input type="checkbox" name="participant_question[]" value="whatever2" class="form-check-input"><label class="form-check-label" for="exampleCheck1">whatever2</label>
</div>
</div>
Luego, en el envío, no sé si lo hace con ajax o no, pero asumiré que no, así que si agrega un ID a su formulario -> id="questionForm"
$(''#questionForm'').submit(function() {
if($(''div.checkbox-group.required div :checkbox:checked'').length > 0) {
return true;//submit the form
} else {
return false; // do not submit the form
}
});
Desafortunadamente, no hay forma de lograr lo que está buscando usando solo html5 , cualquiera que sea la solución que elija, probablemente tenga que hacerlo con js.
Reemplace su getHtmlInput () con esto
public function getHtmlInput($question_id, $index_position, $name = "", $options = "", $required = false, $class = "", $customtype = false) {
//dd($name);
$html = '''';
$html .= $customtype == ''select_menu'' ? "<select name=''participant_question[".$question_id."][".$index_position."]'' class=''form-control'' " . ($required ? " required" : "")
. ">" : '''';
if (empty($options)) {
switch ($customtype) {
case "text":
$html .= "
<input type=''text'' name=''participant_question[".$question_id."][".$index_position."]'' class=''form-control''" . ($required ? " required" : "")
. ">";
break;
case "file":
$html .= "
<input type=''file'' name=''participant_question[".$question_id."][".$index_position."]'' class=''form-control''" . ($required ? " required" : "") . ">";
break;
case "long_text":
$html .= "
<textarea name=''participant_question[".$question_id."][".$index_position."]'' class=''form-control'' rows=''3''" . ($required ? " required" : "") . ">"
. $name .
"</textarea>";
break;
}
} else {
foreach ($options as $option) {
switch ($customtype) {
case "checkbox":
$html .= "
<div class=''form-check''>
<input type=''checkbox'' name=''participant_question[".$question_id."][".$index_position."][]'' value=''" . $option->value . "'' class=''form-check-input''" . ($required ? " required" : "") . ">" .
'' <label class="form-check-label" for="exampleCheck1">'' . $option->value . ''</label>'' .
"</div>";
break;
case "radio_btn":
$html .= "
<div class=''form-check''>
<input type=''radio'' name=''participant_question[".$question_id."][".$index_position."][]'' value=''" . $option->value . "'' class=''form-check-input''" . ($required ? " required" : "") . ">" .
'' <label class="form-check-label" for="exampleCheck1">'' . $option->value . ''</label>'' .
"</div>";
break;
case "select_menu":
$html .= "<option value=''" . $option->value . "''>" . $option->value . "</option>";
break;
}
}
}
$html .= $customtype == ''select_menu'' ? "</select>" : '''';
return $html;
}
y
código blade con este
@if ($allParticipants == 0)
{{ $index_position = 0 }}
@foreach($selectedRtype[''questions''] as $customQuestion)
{{ $question_id = [[QUESTION_ID]] }}
<div class="form-group">
<label for="participant_question">{{$customQuestion->question}}</label>
@if($customQuestion->hasOptions() && in_array($customQuestion->type, [''checkbox'', ''radio_btn'', ''select_menu'']))
{!! $customQuestion->getHtmlInput(
$question_id,
$index_position,
$customQuestion->name,
$customQuestion->options,
($customQuestion->pivot->required == ''1''),
''form-control'',
$customQuestion->type)
!!}
@else
{!! $customQuestion->getHtmlInput(
$question_id,
$index_position,
$customQuestion->name,
[],
($customQuestion->pivot->required == ''1''),
''form-control'',
$customQuestion->type)
!!}
@endif
</div>
{{ $index_position = $index_position+1 }}
@endforeach
@endif
debe configurar el mismo atributo de nombre de las mismas opciones de grupo para que funcione correctamente la opción requerida.
Pero en su código, todas las opciones, incluidas las de diferentes grupos de opciones, comparten el mismo atributo de nombre.
El código anterior no está probado. Pero espero que te funcione.