I've got a number of links containing parameters which will open a dialog which is populated with an ajax call.
sample link:
Attach File
Here's the trigger for the modal:
$(".attach_timesheet_file").on("click", function(e) {
e.preventDefault();
var url = "<?=Yii::app()->createUrl('admin/timesheetNew/attachTimesheet')?>";
var id = $(this).data("id");
var weekStart = $(this).data("week-start");
var weekEnd = $(this).data("week-end");
$.ajax({
type: 'POST',
url:url,
data: {
id: id,
week_start: weekStart,
week_end: weekEnd
},
success: function(data) {
var modal = $("#attachFileModal");
try{
modal.html(data);
}
catch(error)
{
console.log(error);
}
modal.dialog('open');
return true;
}
})
});
The basic action called by the ajax:
public function actionAttachTimesheet(){
$projectId = Yii::app()->request->getPost('id', null);
$reportedWeekStart = Yii::app()->request->getPost('week_start', null);
$reportedWeekEnd = Yii::app()->request->getPost('week_end', null);
$this->renderPartial("_attachTimesheet", [
'projectId' => $projectId,
'reportedWeekStart' => $reportedWeekStart,
'reportedWeekEnd' => $reportedWeekEnd,
'dataProvider' => TimesheetAdditionalFile::additionalFilesDataProvider($projectId, $reportedWeekStart, $reportedWeekEnd)
], false, true);
}
And finally the CGridView widget inside the dialog:
$this->widget('zii.widgets.grid.CGridView', [
'id' => 'files-grid',
'dataProvider' => $dataProvider,
'columns' => [
[
'name' => 'filename',
'header' => 'File Name',
'value' => 'CHtml::link($data["filename"], Yii::app()->baseUrl . TimesheetNew::FILES_FOLDER . $data["filename"], ["class" => ($data["filetype"] == "pdf")?"fancybox_pdf":"fancybox_picture"])',
'type'=>'raw',
'headerHtmlOptions'=>array('style'=>'width: 250px'),
],
[
'class' => 'CButtonColumn',
'template' => '{delete}',
'buttons' => [
'delete' => [
'label' => 'Delete',
'imageUrl' => null,
'url' => 'Yii::app()->createUrl("admin/timesheetNew/deleteFile", ["id" => $data["id"]])'
]
],
'deleteConfirmation'=>'Are you sure you want to delete this file?',
]
]
]);
I've also used qq.FileUploader as well as fancybox inside the modal, but these do not seem to interfere with anything.
When I try to click any such "attach file" link, the dialog opens just fine and everything works as intended. I'm seeing my gridview, and I can add and delete files. However, when I close the dialog, it won't open this link or any other "attach file" links.
The error I'm getting in the console is this after re-clicking a link:
Uncaught TypeError: modal.dialog is not a function
I'm only experiencing this when using the gridview, when I comment out this widget code, I can freely open and close these dialogs at will.
Any help would be greatly appreciated :)
The solution was rather easy. By adding these lines at the top of the view file, dialogs can once again be opened and closed indefinitely.
Yii::app()->getClientScript()
->scriptMap = array(
'jquery.js' => false,
'jquery-ui.min.js' => false
);
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!
I have searched now very long for this but no answers, please help me.
I'm using the highchart-widget from 2amigos in yii2. When I'm creating a view in my controller via "render" the chart shows
and as you can see on the picture on the right the asset is included in the source of the network -> "b732256a - highcharts.src.js"
BUT NOW COMES THE PROBLEM, when I'm rendering the view with "renderAjax" and insert the view in an existing HTML document with ajax -> take a look at my javascript code: the the asset "b732256a - highcharts.src.js" is missing take a look at this foto
But when i access the action direct via browser:
index.php?r=bewt/ladeauswertung&standort=&datum=
it works with renderAjax and render, there is just a problem when i bind the view in an existing html document. im using this routine, to bind the view in an existing html document
document.getElementById("auswertungdetail").innerHTML = jsondata;
What you need to know about my code.
on a html-page there is a button, when the user press this button im calling the following javascript code, and the chart should show up without reloading the whole page
$(document).on('click', '#ladeauswertung', function ()
{
var ausgewaehlterstandort = document.getElementById("standorte").value;
var datum = document.getElementById("datum").value;
$.get("index.php?r=voti/ladeauswertung&standort=" + ausgewaehlterstandort + "&datum=" + datum,
function (jsondata)
{
document.getElementById("auswertungdetail").innerHTML = jsondata;
}
);
});
in my controller im rendering the view:
function actionLadeauswertung($standort, $datum)
{
//some algorithm that do smth with $standort and $datum, not important
$auswertung = 5;
$gesamtauswertung = 10;
return $this->renderAjax('auswertungdetail', ["auswertung" => $auswertung, "gesamtauswertung" => $gesamtauswertung]);
}
and here ist the view which i render in the controller above:
<?php
use dosamigos\highcharts\HighCharts;
?>
<?php echo
HighCharts::widget([
'clientOptions' => [
'chart' => [
'type' => 'bar'
],
'title' => [
'text' => 'Fruit Consumption'
],
'xAxis' => [
'categories' => [
'Apples',
'Bananas',
]
],
'yAxis' => [
'title' => [
'text' => 'Fruit eaten'
]
],
'series' => [
['name' => 'Jane', 'data' => [1, 0, 4]],
['name' => 'John', 'data' => [5, 7, 3]]
]
]
]);
?>
and in my view im calling the 2amigos highchart, it works perfectly with "render" but i wanted to add the view where the highchart is included dynamically when a button is pressed so have to use renderAjax.
PLEASE HELP!!!!!
I'm using yii2 with dropzonejs (perminder-klair/yii2-dropzone)
When i want to initialize the view with some data i got this error,
It seems like the init call is not proccessed
error
dropzone.min.js:1 Uncaught TypeError: this.options.init.call is not a function
at c.init (dropzone.min.js:1)
at new c (dropzone.min.js:1)
at HTMLDocument.<anonymous> (index.php?r=branches/upload:672)
at fire (jquery.js:3187)
at Object.fireWith [as resolveWith] (jquery.js:3317)
at Function.ready (jquery.js:3536)
at HTMLDocument.completed (jquery.js:3552)
my dropzonejs
<?= \kato\DropZone::widget([
'autoDiscover' => false,
'options' => [
'init' => "function(file){alert( ' is removed')}",
'url'=> 'index.php?r=branches/upload',
'maxFilesize' => '2',
'addRemoveLinks' =>true,
'acceptedFiles' =>'image/*',
],
'clientEvents' => [
'complete' => "function(file){console.log(file)}",
// 'removedfile' => "function(file){alert(file.name + ' is removed')}"
'removedfile' => "function(file){
alert('Delete this file?');
$.ajax({
url: 'index.php?r=branches/rmf',
type: 'GET',
data: { 'filetodelete': file.name}
});
}"
],
]);
?>
This plugin use Json::encode function for encoding options and because of this, in your code init encode as string. String is not a function.
You can simply use JsExpression for javascript function to prevent this.
When using yii\helpers\Json::encode() or
yii\helpers\Json::htmlEncode() to encode a value, JsonExpression
objects will be specially handled and encoded as a JavaScript
expression instead of a string.
This code should work.
<?= \kato\DropZone::widget([
'autoDiscover' => false,
'options' => [
'init' => new JsExpression("function(file){alert( ' is removed')}"),
'url'=> 'index.php?r=branches/upload',
'maxFilesize' => '2',
'addRemoveLinks' =>true,
'acceptedFiles' =>'image/*',
],
'clientEvents' => [
'complete' => "function(file){console.log(file)}",
// 'removedfile' => "function(file){alert(file.name + ' is removed')}"
'removedfile' => "function(file){
alert('Delete this file?');
$.ajax({
url: 'index.php?r=branches/rmf',
type: 'GET',
data: { 'filetodelete': file.name}
});
}"
], ]); ?>
it looks like this part in your options overwrites the Dropzone.js init function:
'init' => "function(file){alert( ' is removed')}",
The Yii2 plugin you are using ist simply encoding the options array:
Json::encode($this->options)
So your init is no function it is a string like this:
var options = { "init" : "function(file){alert( ' is removed')}" }
It is not possible to set the init option over this php plugin.
Edit: Thanks #CooPer for the correction, Yii2 isn't my favourite framework so I'm not very familiar with it. It's a good solution.
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 Yii Booster Yii extension for UI. I need to update the content of the tabs using ajax. Using below code I am able to get the content using renderPartial but instead I want to make ajax call and update the content.
$this->widget('bootstrap.widgets.TbTabs', array(
'type' => 'tabs',
'tabs' => array(
array('label' => 'Home', 'content' => $this->renderPartial('home', NULL, true), 'active' => true),
array('label' => 'Test', 'items' => array(
array('label' => 'Sub Tab 1', 'content' => $this->renderPartial('testpage', NULL, true)),
array('label' => 'Sub Tab 2', 'content' => 'some content ')
)),
)
)
);
Do I need to use jquery or something else to work with Yii Booster widgets ?. This is the first time I am using php/yii/extensions.
I am a bit confused so Yii Booster has integrated Bootstrap widgets so that they can be used with php. But for client side do I need to use jquery to manipulate bootstrap widgets ?
Are there any tutorials for using Yii Booster, I know the link to yii booster site, but there we just have simple examples nothing related to events, ajax.
Got this working. As #Sergey said I need to use 'shown' event. I gave ids to each tab to identify specific tab and load content. Here is the code
<?php $this->widget('bootstrap.widgets.TbTabs', array(
'id' => 'mytabs',
'type' => 'tabs',
'tabs' => array(
array('id' => 'tab1', 'label' => 'Tab 1', 'content' => $this->renderPartial('tab1', null, true), 'active' => true),
array('id' => 'tab2', 'label' => 'Tab 2', 'content' => 'loading ....'),
array('id' => 'tab3', 'label' => 'Tab 3', 'content' => 'loading ....'),
),
'events'=>array('shown'=>'js:loadContent')
)
);?>
We have 3 tabs, the content will be loaded using loadContent javascript function.
<script type="text/javascript">
function loadContent(e){
var tabId = e.target.getAttribute("href");
var ctUrl = '';
if(tabId == '#tab1') {
ctUrl = 'url to get tab 1 content';
} else if(tabId == '#tab2') {
ctUrl = 'url to get tab 2 content';
} else if(tabId == '#tab3') {
ctUrl = 'url to get tab 3 content';
}
if(ctUrl != '') {
$.ajax({
url : ctUrl,
type : 'POST',
dataType : 'html',
cache : false,
success : function(html)
{
jQuery(tabId).html(html);
},
error:function(){
alert('Request failed');
}
});
}
preventDefault();
return false;
}
Here we get the target, that should be the anchor element of the tab that we clicked, get the href value which should be the id that we configured. Decide the url based on this id, load content and update the div's. The id of div's are the same as href.
I haven't found way to load content of the initial active tab, there should be way to fire loadContent function, for now I have used renderPartial to get the content instead
I extended the TbTabs class with #Abdullahs example. It's tested with YiiBooster, but should work with other Bootstrap plugins as well.
Usage:
$this->widget(
'ext.ajaxTabs.widgets.ajaxTabs',
array(
'reload' => true, // Reload the tab content each time a tab is clicked. Delete this line to load it only once.
'tabs' => array(
array(
'label' => 'Static',
'content' => 'Static content'
),
array(
'label' => 'Static rendered',
'content' => $this->renderPartial('index', null, true),
),
// And finally AJAX:
array(
'label' => 'AJAX',
'content' => 'loading ....',
'linkOptions' => array('data-tab-url' => Yii::app()->createAbsoluteUrl('site/'))
)
),
)
);
/protected/extensions/ajaxTabs/widget/ajaxTabs.php:
<?php
Yii::import('bootstrap.widgets.TbTabs');
class ajaxTabs extends TbTabs
{
/**
* #var bool Reload the tab content each time the tab is clicked. Default: load only once
*/
public $reload = false;
public function run()
{
$id = $this->id;
/** #var CClientScript $cs */
$cs = Yii::app()->getClientScript();
$cs->registerScript(
__CLASS__ . '#' . $id . '_ajax', '
function TbTabsAjax(e) {
e.preventDefault();
var $eTarget = $(e.target);
var $tab = $($eTarget.attr("href"));
var ctUrl = $eTarget.data("tab-url");
if (ctUrl != "" && ctUrl !== undefined) {
$.ajax({
url: ctUrl,
type: "POST",
dataType: "html",
cache: false,
success: function (html) {
$tab.html(html);
},
error: function () {
alert("Request failed");
}
});
}
if(' . ($this->reload ? 0 : 1) . '){
$eTarget.data("tab-url", "");
}
return false;
}'
);
$this->events['shown'] = 'js:TbTabsAjax';
parent::run();
}
}
Its a new version to loadContent
function loadContent(e){
var targetUrl = e.target.getAttribute('data-tab-url');
var contentID = e.target.getAttribute('href');
$(contentID).load(targetUrl, function(){
$('.tabs').tabs(); //reinitialize tabs
});
e.preventDefault();
return false;}