jQuery change not triggering after DIV has already been loaded, using CakePHP - php

When a room_id is selected from the drop down, I use the JS helper to populate the security_deposit and room_rate inputs. The issue is that if I select a room_id, the room_rate_update jQuery change function stops working. However, when page loads and I don't select a room_id, I can type in the room_rate box and it's triggered, but not after I select a room_rate.
The one thing that I think may be causing this is when I select a room_id, the entire div containing the room_rate is updated. It was previously generated by the CakePHP form helper, however, I made sure that the div is replaced by the exact same name, class, id, etc... It's identical to the one that appears when the page loads
Here is the form in my view
echo $this->Form-create('Arrival');
echo $this->Form->input('room_id',array('options' => $room_numbers, 'label'=>'Room Number'));
?>
<div id="room_rate_update">
<?php
echo $this->Form->input('room_rate', array('label' => 'Room Rate (numbers only)'));
?>
</div>
<div id = "security_deposit_update">
<?php
echo $this->Form->input('security_deposit',array('label' => 'Security Deposit (numbers only)'));
?>
</div>
<?php
echo $this->Form->input('balance_upon_arrival',array('label' => 'Balance Due Upon Arrival'));
Here is the JS helper and jQuery function for the updates
//if someone changes the room_rate, this should update the deposit amount
$(document).ready(function(){
$("#ArrivalRoomRate" ).change(function() {
alert('test');
});
});
//populates the room rate when the room is selected
$this->Js->get('#ArrivalRoomId')->event('change',
$this->Js->request(array(
'controller'=>'Arrival',
'action'=>'getRoomRate'
), array(
'update'=>'#room_rate_update',
'async' => true,
'method' => 'post',
'dataExpression'=>true,
'data'=> $this->Js->serializeForm(array(
'isForm' => false,
'inline' => true
))
))
);
Here is the view for the JS helper POST request
//room_rate_update.ctp
<div class="input text required">
<label for="ArrivalRoomRate">Room Rate </label><input name="data[Arrival][room_rate]" maxlength="10" type="text" id="ArrivalRoomRate" required="required" value="<?php echo $room_rate; ?>">
</div>
So, as I stated. Prior to selecting a room_id, the "test" is triggered. After I select a value

You should have another function, for instance :
function init ()
{
$("#ArrivalRoomRate" ).change(function() {
alert('test');
});
}
After all content refreshed, then call it once. Otherwise, when all content refreshed, this event handler will be invalid for new content, coz it's partial rendering.

You can try with a delegate(aka live) event handler like following:
$(document).ready(function(){
$("body" ).on("change", "#ArrivalRoomRate", function() {
alert('test');
});
});
If you have problem with .on() with jQuery version, then you can use .live() with old jQuery like following:
$("#ArrivalRoomRate").live("click", function() {
alert("test");
});

Related

Adding some more fields to the form in yii2 using ajax

I have a Yii2 form:
<?php $form = ActiveForm::begin(['id' => 'que']); ?>
<?php echo $form->field($model, 'type')
->dropDownList($questionTypes, [
'class' => 'form-control ng-pristine ng-valid ng-touched',
'prompt' => 'Select question type',
'ng-model' => 'que.type',
'ng-change' => 'addAnswerOptions(que);',
]);
?>
<?php ActiveForm::end(); ?>
On the basis of selected dropdown value, I have to add some more fields to the same form of the same model. What fields will be added, is totally depend on the dropdown value.
How can I do this?
From the information you give out here is what I would suggest.
1) Dynamic - no AJAX
Build your form with all the fields you need, just contain each "scenario" in a separate div like follows:
<?php $form = ActiveForm::begin(['id' => 'que']); ?>
<?php echo $form->field($model, 'type')
->dropDownList($questionTypes, [
'class' => 'form-control ng-pristine ng-valid ng-touched',
'prompt' => 'Select question type',
'ng-model' => 'que.type',
'ng-change' => 'addAnswerOptions(que);',
]);
?>
<div class="form-option" data-type="class" style="display:none;">
<?php
// ... fields here for case type == class
?>
</div>
<div class="form-option" data-type="prompt" style="display:none;">
<?php
// ... fields here for case type == prompt
?>
</div>
<div class="form-option" data-type="ng-model" style="display:none;">
<?php
// ... fields here for case type == ng-model
?>
</div>
<div class="form-option" data-type="ng-change" style="display:none;">
<?php
// ... fields here for case type == ng-change
?>
</div>
<?php ActiveForm::end(); ?>
Then you will want to register Javascript code to display the correct blocs depending on which dropdown option was selected.
Bellow is an example using JQuery:
$(document).ready(function(){
$('select.form-control').change(function(){
$('.form-option').hide(); // hide all options if an option is showing
var index = $('select.form-control').index();
$('div[data-type="'+index+'"]').show(); //show the correct fields
});
});
If you're going to go this way I suggest you use AJAX validation for your form. It will avoid you having to deal with a headache on page reload.
Once your form is submitted you will have to handle each case in your controller. You can either use a simple set of if() statements that check the drop down value. Or you can set your model validation scenario according to the drop down value.
The advantage of this is that it will be quicker and you will be able to take advantage of ActiveForm. the cons are that you need to know which fields you want to display for each option, and it doesn't allow you to cumulate n number of fields when you don't know how much n is.
2) Using Ajax
In the event that you want to use ajax calls to load the extra form fields you will have to make a controller/action combination that will return the fields depending on the type that you pass in the GET
This action will generate the html of the fields you want to display. Here's an example:
public function actionAjaxFields($type)
{
$html = '';
if($type == "class")
{
$html .= Html::textInput('Field1');
}
elseif($type == "prompt")
{
$html .= Html::textInput('Field2');
}
else
{
// etc...
}
return $html;
}
Note that you can also pass a user id to this method which will allow you to generate a model and use Html::activeTextInput(), however you will not be able to take advantage of ActiveForm features.
Once this is done, you should bind a function to the change event of the dropdown and use something along the lines of :
var responsePromise = $http.get("controller/ajax-fields", {params: {type: <type-from-dropdown>}});
Unfortunately I do not know much about angularjs so this is the extent of the help I can give on the javascript side of things. I'm sure there's more than enough information on google/stackoverflow about binding events and appending data to the DOM in angularjs to get you running.
Let me know if I can be of any extra help on the Yii2 side.

Yii ajax jquery multiple request just fist one works

Many input field and button pairs for ajax request works only for first time. After first request-response other buttons doesn't call ajax function.
There's a data grid list. Each row has a Title field (as input) with a button to call ajax function for updating this field and refresh list.
first time I click on one of the buttons everything works fine, data sends and list refresh with new data. but after this when I click on one of the buttons nothing happens , even function doesn't call.
Where I'm doing mistake?
My ajax function:
$('.titleBtn').click(function(event){
var id = $(this).attr('name');
var title = $('#' + id).attr('value');
var formAction = '".$this->createUrl('article/changeTitle')."';
$.get(formAction,{id:id,title:title},function(result){
$.fn.yiiGridView.update('article-grid');
}
);
event.preventDefault();
});
My grid list:
<?php $form=$this->beginWidget('CActiveForm', array(
'action'=>Yii::app()->createUrl($this->route),
'method'=>'get',
'id'=>'Artform',
)); ?>
<?php $this->widget('bootstrap.widgets.TbGridView', array(
'id'=>'article-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'ID',
array(
'header'=>Yii::t('labels','Title'),
'name'=>'Title',
'type'=>'raw',
'value'=> function($data) use ($model) {
return '<input type="text" id="'.$data->ID.'" value="'.$data->Title.'"><button type="button" name="'.$data->ID.'" class="titleBtn" >Update</button>';
},
),
....
),
)); ?>
//Some buttons irrelevant to this subject for submitting whole list.
<?php $this->endWidget('CActiveForm'); ?>
You could set the event using delegate
$('#Artform').delegate('.titleBtn', 'click', function() {
...
});
You need to add afterAjaxUpdate option to your TbGridView and add js code to invoke after ajax update and set your handlers.

Cakephp best way to create secret input

Okay so i have a combobox with two options.
Now if one of the options is selected a new input field should appear.
echo $this->Form->input('group_id', array( 'id' => 'groupId'));
echo $this->Form->input('clientid',array( 'type' => 'hidden', 'id' => 'id_client',));
And for that i would use Jquery to check the values
<script>
$(document).ready(function () {
$("#groupId").change(function () {
if($(this).val() == 2){
// do set visible
}
})
});
</script>
My question is: how can i change the type of the field to visible? i have tried: $('#groupId').show(); also $('#clientid').get(0).type = 'text';
But didnt seem to work and i am starting to wonder if this is the best way of doing such a thing?
$(this).attr('type', 'text');
You're doing it wrong.
type="hidden" is not appropriate to hide UI elements (form fields or anything else).
You should instead use the CSS attribute display. Change your clientid input type to "text". When groupId is not 2, set display: none on your clientid input. When it's 2, set display: block.
With jQuery, you can use $('#clientid').show() and .hide().
For instance:
<select id="groupId"><!-- options... --></select>
<input type="text" id="clientId" />
<script>
$(document).ready(function () {
function showHideClient() {
var show_client = $(this).val() == 2;
$("#clientId").toggle(show_client); // hide or show
}
// we bind the "change" event to the hide/show checking
$("#groupId").change(showHideClient);
// and we call it at page load to hide the input right away if needed
showHideClient();
});
</script>

Jquery Raty start plugin : set score for multiple div

I am using jquery star rating plugin "Raty" https://github.com/wbotelhos/raty.
i am generating a result set from database with PHP. that includes score also. I want set score property for every individual rating component. how can I do that?
I am using this syntax for showing the stars.
$('.stars_small').raty({
readOnly : true,
half : true,
score : 2,
space : false
});
<div class="stars_small"></div>
there are many div in a single page with the class "stars_small" generated dynamically. I want to set "score" for every div.
$('.stars_small').raty({
readOnly : true,
half : true,
score: function() {
return $(this).attr('data-rating');
}
space : false
});
this worked fine for me.
the plugin is adding a hidden textbox in every div with class="stars_small"
like this
<div class="stars_small">
<input type="hidden" name="score" value="3.5" readonly="readonly">
</div>
So I just set the value attribute with number coming from database query.
Try this
$('.stars_small').each(function() {
$(this).raty({
readOnly : true,
half : true,
score : 2,
space : false
});
});
Assuming that you have generated with PHP the JS lines:
// lines of JS generated with a loop in PHP (for the rate content)
var rates = [];
rates.push({...one rate coming from PHP...});
rates.push({...one rate coming from PHP...});
// etc...
You can run you rating star with :
$(document).ready(function() {
$(".starts_small").each(function(index, element) {
$(this).raty(rates[index]);
});
});
Here is what i did:
I created a separate class for each of those star divs:
<div class="star s0"></div>
<div class="star s1"></div>
<div class="star s2"></div>
I also generate the array of values in my template (that is, pass the values from my server-side script to the web page). Like so:
var array = new Array(2.4, 2.9, 5.0);
And then I declare the thing common for all the three "star banners" in the $(".star") call, and set the values in a cycle:
$('.star').raty({
half : true
});
for (i = 0; i < array.length; i++) {
$('.s' + i).raty({
score:array[i]
});
}
For V.2.7 Jquery raty is the form:
If you need to start you score depending of a dynamic value, you can to use callback for it.
You can pass any value for it, not necessarily a data- value. You can use a field value for example.
<div data-score="1"></div>
$('div').raty({
score: function() {
return $(this).attr('data-score');
}
});

jQuery - Drag and drop List reordering

I have a HTML list that I'd like to allow the user to be able to re-order through drag-and-dropping, and then submit their changes to the database.
I'm happy with all the database stuff, but I'm struggling with the Javascript/JQuery.
I've currently got jQuery UI Sortable working fine (so the other and re-order elements via drag-and-drop), but I don't know how to go about getting the new order for the SUBMIT.
Can anyone help? If you need more information, just say. Thanks!
send that data to your application via an AJAX call for example
$('#TabContainer').tabs();
$('#TabContainer .ui-tabs-nav').sortable({
axis: 'x',
update: function(event, ui){
var data = $('#TabContainer .ui-tabs-nav').sortable('serialize');
$.ajax({
url: '/events/update-tab-order',
data: data,
type: 'POST',
mode: 'abort'
});
}
});
The only tricky part is that you must specify an ID on the list items in the format of groupname_identifier. For example:
<div id="TabContainer">
<ul>
<li id="MyTabs_123">Tab 1</li>
<li id="MyTabs_124">Tab 2</li>
...etc
</ul>
...tab content goes here
</div>
Then when your application receives the POST data, it will be an array that looks like this:
$_POST['MyTabs']
array(
0 => '123',
1 => '124'
)
Take a look # serialize(), I made the same thing without an explicit submit button, but directly inject the order by ajax using mootools.
<script language="javascript">
<!--
window.addEvent('domready', function() {
var thisSortables = new Sortables($('list'), {
constrain: true,
clone: true,
revert: true,
onStart: function() {
$('confirm').set('html', '');
},
onComplete: function() {
this.serialize(function(el, index) {
var updateOrderRequest = new Request.HTML({
url: '../module/tools/admgn/dbsorter.php',
method: 'post',
data: {'itemID': el.id.replace("item_",""), 'new_pos':(index+1)}
}).send();
});
$('confirm').set('html', 'Reihenfolge erfolgreich gespeichert.');
}
});
});
-->
</script>
Maybe you get the idea how you can make it work.
Since <UL> and <OL> is not form element you cannot get through post method , I hope you can do by this
http://quasipartikel.at/multiselect_next/
make all options as selected and hide the available part as hidden

Categories