I have a form with tags which have dependencies with a category field
Category 1
tag a
tag b
tag c
Category 2
tag d
tag e
tag f
...
When loading the page, I have "Category 1" and "the list of his tags"
Then when I change the category to "Category 2", I replace the list of tags via ajax.
When I submit the form, I get "This value is not valid". I guess that it's because the fact that the form expect values from the initial list.
So, I don't know how to proceed to get my tags to be validated.
Here is the code which generate the form
->add('category', null, array(
'choices' => $this->cat_tree,
'label' => 'Category',
'required' => true,
'empty_value' => '',
))
->add('tags', 'entity', array(
'class' => 'MyappServicesBundle:Category',
'query_builder' => function(EntityRepository $er) use ($parent_id) {
return $er->createQueryBuilder('c')
->where('c.parent = :parent_id')
->setParameter('parent_id', $parent_id)
->orderBy('c.title', 'ASC');
},
'required' => false,
'multiple' => true,
'expanded' => true,
'label' => 'Tags',
))
And here is the ajax code which replace the tags list
$('#myapp_servicesbundle_category').change(function() {
$.post(
"/tag/ajax/search",
{ parent_id: $(this).val() },
function( data ) {
var newtags = '';
jQuery.each( data, function( i, val ) {
newtags += ' <input type="checkbox" value="'+val.id+'" name="myapp_servicesbundle[tags][]" id="myapp_servicesbundle_tags_'+val.id+'">';
newtags += ' <label for="myapp_servicesbundle_tags_'+val.id+'">'+val.label+'</label>';
});
$('#myapp_servicesbundle_tags').html(newtags);
}, "json"
);
});
Thanks in advance for your help
from my experience you have to use an eventListener in Symfony. There is a quite clear example in the doc (more detailed in english than in french, be careful).
http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data
Related
So what I want to do is populate a dropdown in Yii framework with ajax using my database values in drop down. I using Kartik widget in it here is my dropdown code,
<?php $primaryfield = [1 => 'Business Development(Sales)', 2 => 'Graphic Design', 3 => 'Social Media Marketing', 4 => 'Web Development']; ?>
<?= $form->field($model, 'primaryfield')->widget(Select2::classname(), ['data' => $primaryfield,
'options' => ['placeholder' => 'Enter Your Primary Field', 'multiple' => false], 'pluginOptions' => ['tags' => false, 'tokenSeprators' => [',', ' '], 'maximumInputLength' => 20],])->label(false); ?>
I know everything about Ajax in PHP but don't know how to use it in Yii framework using Kartik widget I have all the primary fields value in my database but unfortunately, I am only able to display them in static basis not dynamic basis using ajax
If I get you clear, you want to have a drop-down list in which their items are dynamically generated by your database.
This is the way you can achieve with kartik dropdown widget.
I'll first create active form field which contains predefined categories as follows
<?php $form = ActiveForm::begin();
//Initialize predefined categories
$data = [
'1' => 'Business Development(Sales)',
'2' => 'Graphic Design',
'3' => 'Social Media Marketing',
'4' => 'Web Development',
];
?>
These field will prompt database to retrieve items for particular category via AJAX
<?= $form->field($model, 'primaryfield')->widget(Select2::classname(), [
'data' => $data,
'options' => ['placeholder' => 'Enter your primary field'],
'pluginOptions' => [
//'allowClear' => true
],
'pluginEvents' => [
"change" => "function() {
var id = $(this).val(); //extract the id of selected category
$.ajax({
method : 'GET',
dataType : 'text',
url : '../yourcontroller/populate?id=' + id,
success : function (response) {
var response = JSON.parse(response);
var myDropDownList = document.getElementById(\"model-item\");
$.each(response, function(index, value) {
var option = document.createElement(\"option\");
option.text = value;
option.value = index;
try {
myDropDownList.options.add(option);
}
catch (e) {
alert(e);
}
});
}
});
}",
],
]);
?>
<?= $form->field($model,'item')->dropdownList(
['prompt'=>'Select Item']
);
?>
Now create action in your controller that will query items from your database based on the category selected and return it to the Item field via ajax.
<?php
public function actionPopulate($id)
{
// the id above is the one selected from the category field so you can use
// that Id now to retrieve items from your item-field with ajax
/* in you case */
$results = Category::find()
->select('items')
->where(['id' => $id])
->asArray()
->all();
//these hard-coded values are for the demonstration
$results = [
'1'=>'maziwa',
'2'=>'ugali',
'3'=>'samaki',
'4'=>'kuku',
'5'=>'mtetea',
];
return json_encode($results);
}
?>
Hope this helps!
For example I have an entity field which starts null and will show the radio buttons, within the Admin pages once a radio button has been selected and saved into the entity then those radio buttons need to be 'disabled', still visible but not intractable.
protected function configureFormFields(FormMapper $form)
{
$form->add('radio_buttons', ChoiceType::class,
array('choices' => array(
"choice 1" => 'input1',
"choice 2" => 'input2'),
'choices_as_values' => true, 'multiple'=>false, 'expanded'=>true, 'disabled' => false));
}
Your can put a condition in your form to check wether a field is already filled or not.
(Assuming the method is named getRadioButton())
if ($this->getSubject()->getRadioButton() != null) {
$form->add(here tell than you need disabled buttons)
} else {
$form->add(here tell than you need buttons)
}
also, in form field, you can add "html" attribute doing this:
->add('radio_buttons', ChoiceType::class,array(
'what you want'=>'ok',
'attr'=>array("disabled" => true))
so finally it'd give something like
if ($this->getSubject()->getRadioButton() != null) {
$form->add('radio_buttons', ChoiceType::class,
array('choices' => array(
"choice 1" => 'input1',
"choice 2" => 'input2'),
'choices_as_values' => true,
'multiple'=>false,
'expanded'=>true,
'attr' => array('disabled'=>true),
));
} else {
$form->add('radio_buttons', ChoiceType::class,
array('choices' => array(
"choice 1" => 'input1',
"choice 2" => 'input2'),
'choices_as_values' => true,
'multiple'=>false,
'expanded'=>true,
));
}
For more information:
https://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/form_field_definition.html
Do it in your view.
Check if one of the choice exists, and implement a different code if it does.
I would also recommand to remove the radio buttons if it exists, and replace with a text. That will prevent some smartass to edit the DOM and change the choice.
I'm using select2 to let user choose stuff from list from ajax.
In adding to db it's working great, but I want to edit stuff. So I can still select stuff from my select2, but user should see what is the current value of select2.
I've tried to do something with InitSelect, but it didn't work, even after I've just passed data from php.
This is my Select2:
$(".personid").select2({
ajax: {
type: "post",
url: '/' + APP_PATH + '/Projects/find_person.json',
datatype: 'json',
quietMillis: '100',
data: function (term, page) {
return {
q: term.toUpperCase(), // wprowadzony ciag znakow - zawsze na uppercase
page_limit: 10,
};
},
results: function (data, page) {
var dane = {results: []};
$.each(data['data'], function (i, item) {
dane.results.push({
id: item['Person']['id'],
text: item['Person']['displayName']
});
});
return dane;
}
}
});
And this is my cake form input:
echo $this->Form->input('person_id', array(
'type' => 'text',
'value' => $projectcontact['Person']['id'],
'Placeholder' => 'Wybierz osobę',
'empty' => 'Wybierz osobę ',
'class' => 'form-control personid',
'label' => array(
'class' => 'col-md-4 control-label',
'text' => 'Osoba'
)
));
Can anyone help to make Select.js display current Persona name data from database in this?
With Select2 4.x
With Select2 4.x you're not supposed to use a text input element anymore, but a select element. Quote from the docs:
When using Select2 with remote data, the HTML required for the select is the same as any other Select2. If you need to provide default selections, you just need to include an option for each selection that contains the value and text that should be displayed.
<select class="js-data-example-ajax">
<option value="3620194" selected="selected">select2/select2</option>
</select>
https://select2.github.io/examples.html#data-ajax
So, as described, create a proper select input with a single selected option element, something along the lines of:
echo $this->Form->input('person_id', array(
'type' => 'select',
'options' => array(
$projectcontact['Person']['id'] => $projectcontact['Person']['displayName']
),
'selected' => $projectcontact['Person']['id'],
'class' => 'form-control personid',
'label' => array(
'class' => 'col-md-4 control-label',
'text' => 'Osoba'
)
));
Additionally you'll have to ensure that $projectcontact is being filled with the person according to the possible submitted person_id value, otherwise the selected value will not remain when rendering the form after submit.
Normally when creating a select element, you'd use a complete list of options, so that the form helper could pick the appropriate option automatically, based on the submitted value. Without such a list, you'll have to read and supply the specific person instead.
Here's some dummy code that demonstrates the priniciple:
$personId = $defaultPersonId;
if($this->request->is(array('post', 'put'))) {
$personId = $this->request->data('ModelName.person_id');
// ...
}
$projectcontact = $this->Person->findById($personId);
$this->set('projectcontact', $projectcontact);
See also
Cookbook > Core Libraries > Helpers > Form > Options for select, checkbox and radio inputs
Cookbook > Core Libraries > Helpers > Form > Creating form elements
Cookbook > Models > Retrieving Your Data > find(‘list’)
I am trying to create a dependent combobox system in my Yii application.
First combobox is populated with States and the second one is dynamically generated with ajax and renderPartial() method.
Code below:
View
<?php
$this->widget('ext.combobox.EJuiComboBox', array(
'model' => $adMulti,
'attribute' => 'state_id',
// data to populate the select. Must be an array.
'data' => CHtml::listData(State::model()->findAll(), 'id', 'name'),
'assoc' => true,
// options passed to plugin
'options' => array(
// JS code to execute on 'select' event, the selected item is
// available through the 'item' variable.
'onSelect' => 'getCities(item.value);',
// If false, field value must be present in the select.
// Defaults to true.
'allowText' => false,
),
// Options passed to the text input
'htmlOptions' => array(
'style' => 'height: 36px',
),
));
?>
<script type="text/javascript">
function getCities(state) {
$.ajax({
url: '<?php echo $this->createUrl('ad/ajaxCities'); ?>',
data: {state_name: state},
type: 'POST',
success: function (data) {
$('#city_id-carrier').html(data);
}
});
}
</script>
<div id="city_id-carrier" class="textboxes"></div>
AdController
public function actionAjaxCities()
{
$stateName = isset($_POST['state_name']) ? $_POST['state_name'] : FALSE;
if ($stateName) {
$state = State::model()->findByAttributes(array(
'name' => $stateName
));
$stateId = $state->id;
$cities = City::model()->findAllByAttributes(array(
'state_id' => $stateId
));
$this->renderPartial('_cities', array(
'cities' => $cities,
'stateId' => $stateId
), FALSE, TRUE
);
}
}
_cities.php
<?php
$this->widget('ext.combobox.EJuiComboBox', array(
'model' => AdMulti::model(),
'attribute' => 'city_id',
// data to populate the select. Must be an array.
'data' => CHtml::listData($cities, 'id', 'name'),
'assoc' => true,
// options passed to plugin
'options' => array(
// JS code to execute on 'select' event, the selected item is
// available through the 'item' variable.
// 'onSelect' => 'getLocalities(item.value);',
// If false, field value must be present in the select.
// Defaults to true.
'allowText' => false,
),
));
?>
The code is working and creating the combobox for the first time. But when I change the value in state combobox, something weird happens. A new combobox is created, but the values shown are still from the first combobox generated.
I am getting an error "TypeError: this.input is undefined" in Firebug Console.
I tried creating unique id for combobox using uniqid() but it isn't affecting the id of select element of the combobox.
If I change
$('#city_id-carrier').html(data)
to
$('#city_id-carrier').append(data)
it is working well but with multiple combobox generated.
Any ideas/suggestions to make this work?
I've found a solution to get this working. Instead of creating the combobox dynamically, place the combobox once and then populate it dynamically upon each request. Much like dependent dropdown.
A combobox is a combination of a dropdown and textbox. So, note down the id of the hidden dropdown and update it upon ajax update.
Code:
View:
<?php
$this->widget('ext.combobox.EJuiComboBox', array(
'model' => $adMulti,
'attribute' => 'state_id',
// data to populate the select. Must be an array.
'data' => CHtml::listData(State::model()->findAll(), 'id', 'name'),
'assoc' => true,
// options passed to plugin
'options' => array(
// JS code to execute on 'select' event, the selected item is
// available through the 'item' variable.
'onSelect' => 'getCities(item.value);',
// If false, field value must be present in the select.
// Defaults to true.
'allowText' => false,
),
));
?>
<script type="text/javascript">
function getCities(state) {
$.ajax({
url: '<?php echo $this->createUrl('ad/ajaxCities'); ?>',
data: {state_id: state},
type: 'POST',
beforeSend: function() {
$('#AdMulti_city_id_combobox').val(''); // emptying textbox in case a value is previously selected.
},
success: function (data) {
$('#AdMulti_city_id').html(data); // populating the hidden dropdown.
}
});
}
</script>
<?php
$this->widget('ext.combobox.EJuiComboBox', array(
'model' => $adMulti,
'attribute' => 'city_id',
// data to populate the select. Must be an array.
'data' => CHtml::listData(array(''), 'id', 'name'),
'assoc' => true,
// options passed to plugin
'options' => array(
'allowText' => false,
),
));
?>
AdController
public function actionAjaxCities()
{
$stateName = isset($_POST['state_id']) ? $_POST['state_id'] : FALSE;
if ($stateName) {
$state = State::model()->findByAttributes(array(
'name' => $stateName
));
$cities = City::model()->findAllByAttributes(array(
'state_id' => $state->id
));
$data = CHtml::listData($cities, 'id', 'name');
foreach ($data as $id => $name) {
echo CHtml::tag('option', array('value' => $id),
CHtml::encode($name), TRUE);
}
}
}
I am using symfony2 and bootstrap 3 and when I set the readonly attribute to a form field, it gets greyed and I have the forbidden cursor but the field is still editable (in my case a select dropdown).
The readonly attribute would work great for a simple text field, but not for a select.
How can I make sure users can't click a select and change its value ?
I can't use "disabled" as I need the value to be passed to the form.
Using jquery to rewrite the readonly attribute also did not work.
my form:
->add('product', 'entity', array(
'label' => 'Produit',
'class' => 'AppBundle:MarketPlace\Product',
'read_only' => true,
))
Create a data transformer ProductToTextTransformer for your entity as explained in the doc, and then use it in your formbuilder, adding a select or a readonly text according to the condition for the select to be disabled or not :
//...
// this assumes that the entity manager was passed in as an option
$entityManager = $options['em'];
$transformer = new ProductToTextTransformer($entityManager);
if ($condition_to_disabled_the_select){
$builder->add('product', 'entity', array(
'label' => 'Produit',
'class' => 'AppBundle:MarketPlace\Product',
));
}
else{
$builder->add(
$builder->create('product', 'text', array('label' => 'Produit', 'read_only' => true))
->addModelTransformer($transformer)
);
}
The following is working but I don't liek it that much, I feel it's not clean like it should be:
<script>
$(function(){
$(':input[readonly]').each(function(){
$(this)
.hide()
.parent().append('<p>' + $(this).find(":selected").text() + '</p>')
})
;
})
</script>