I am totally confused about how should i save tag_id and post_id in the table when I still don't have the post_id. I made dropdownlist with options from database table
<?= Html::activeDropDownList($model, 'post_id', $ddItems, ['class' => 'form-control dd-list', 'prompt' => '']) ?>
That list contains tags(PHP, Java etc.).
User can have up to 3 tags on post. I tried to pass tags through GET and take in the controller with \Yii:$app->request->get(['id']) but without result.
my jQuery:
var ddList = $('.dd-list');
var tagList = $('.tag-container');
ddList.on('change', function () {
var tagHolder = document.createElement('div');
tagHolder.setAttribute('class', 'tag-holder');
var selected = $('.dd-list option:selected').text();
tagHolder.setAttribute('id', selected);
console.log(selected);
if(tagList.find('div').length > 2){
alert('You can have most 3 tags!');
return false;
}
if(tagList.find('#'+selected).length){
return false;
}else{
tagHolder.append(selected);
tagList.append(tagHolder);
$.ajax({
type : 'GET',
dataType : 'text',
url : '../post/create?tag=' + selected
});
}
});
actionCreate :
public function actionCreate()
{
$model = new Post();
$id = \Yii::$app->user->identity->id;
$ddItems = ArrayHelper::map(Tag::find()->all(),'tag_id', 'tag_name');
if ($model->load(Yii::$app->request->post())) {
date_default_timezone_set('Europe/Berlin');
$param = \Yii::$app->request->get();
$model->user_id = $id;
$model->date_create = date('m/d/Y');
if($model->save())
{
$tag = \Yii::$app->request->get(['tag']);
return $this->redirect(['view', 'id' => $model->post_id]);
}
throw new \yii\db\Exception("Some problem with DB connection ocurred!");
} else {
return $this->render('create', [
'model' => $model,
'ddItems' => $ddItems
]);
}
}
I am getting error : undefined tag. I am trying to get only one tag (because still don't know how to pass more).
What is the right way to reach my goal? I am in total mess from about 1 day! Ton of thanks in advance!
EDIT
I tried to send that tag with on click event like this :
$('.create-post').on('click', function () {
var tag = $('input[name=chosen-tag]').val();
console.log(tag);
$.ajax({
type : 'GET',
dataType : 'text',
url : '../post/create?tag=' + tag
});
});
I could not understand your programming scenario, But..
Change
$tag = \Yii::$app->request->get(['tag']);
To
$tag = \Yii::$app->request->get('tag');
Related
Solution
Since the php is not going to be re-executed someone told me to use a return value from the controller as a parameter of the "success" function into ajax's request.
**CONTROLLER**
if(Yii::$app->request->isAjax){
$query = new \yii\db\Query();
$rows = $query->select([])
->from('task')
->where('date(start) <= date(\'' . $this->request->getBodyParam('start_date') . '\')')
->all();
$items = "";
foreach (ArrayHelper::map($rows,'id','name') as $key => $value)
$items .= '<option value="'. $key .'">'. $value .'</option>\n';
//<option value="16">test</option> example output
echo $items;
}
VIEW
$this->registerJs("$('#task-start').on('change',function(){
$(\".btn, .btn-success\").prop(\"disabled\",true);
var date = $(this).val();
$.ajax({
url: \"".Yii::$app->request->baseUrl."/task/create\",
data: {start_date: date},
type: \"post\",
success: function(dependency_options){
//dependency_options contains what's returned with 'echo' from the controller
$('#task-dependencies').find('option:not(:first)').remove();
$('#task-dependencies').append(dependency_options);
$(\".btn, .btn-success\").prop(\"disabled\",false);
},
error: function () {
console.log('ERROR')
$(\".btn, .btn-success\").prop(\"disabled\",false);
}
});
});",View::POS_READY);
Hoping this might help someone.
My problem
I have a DropDownList with no elements and I want to update the list with elements coming from a Query whenever the user changes the datepicker without refreshing the page.
An example of something similar to this would be those forms in which you type your region and it changes the dropdownlist based on what you choose on the field before.
Maybe I'm using a wrong approach to this cause I'm still new to the MVC model and the Yii2 framework so any idea on how to change it's well appreciated.
What I've tried
With this code below as is I had issues cause after the form was created the first time I could not change it later, I've tried to change the html, as you can see from the script in the success ajax function of the View but the script was executed only the first time the view was loaded.
Controller calling the render
public function actionCreate()
{
$model = new Task();
if(Yii::$app->request->isAjax){
$query = new \yii\db\Query();
$rows = $query->select([])
->from('task')
->where('date(start) <= date(\'' . $this->request->getBodyParam('start_date') . '\')')
->all();
$items = ArrayHelper::map($rows,'id','name');
$model->setItems($items);
return $this->renderPartial('_form',[
'partial' => true,
'model' => $model
]);
}
else if ($this->request->isPost) {
..unnecessary code..
return $this->render('create', [
'model' => $model,
]);
}
The view "create" basically renders the view _form (autogenerated by Gii)
View _form
<?php
//Here it takes the items in the model
//(which will contain the new items to append after ajax call)
$objects = json_encode($model->getItems() ?? []);
var_dump($model->getItems() ?? []);
//Here whenever the datepicker is change will fire ajax request
$this->registerJs("$('#task-start').on('change',function(){
var date = $(this).val();
var items = ". json_encode($model->getItems() ?? []) .";
alert(items);
$.ajax({
url: \"".Yii::$app->request->baseUrl."/task/create\",
data: {start_date: date},
type: \"post\",
success: function(){
//$('#task-dependencies').find('option:not(:first)').remove();
$.each(items, function(key, value) {
$('#task-dependencies')
.append($('<option>', { value : key })
.text(value));
});
},
error: function () {
console.log('ERROR')
}
});
});",View::POS_READY);
?>
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'start')->widget(\kartik\date\DatePicker::className(), [
...datepicker that triggers onChange...
]) ?>
//The dropdownlist that should dynamically change
<?= $form->field($model, 'dependencies')->dropDownList(
$model->getItems(),
['prompt' => 'Seleziona una o piĆ¹ dipendenze', 'multiple' => true, 'selected' => 'selected'] // options
);
?>
<?php ActiveForm::end(); ?>
</div>
<script src="https://cdn.jsdelivr.net/npm/jquery#3.6.0/dist/jquery.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css">
You can use Pjax in, yii2:
Controller:
public function actionCreate() {
$model = new Task();
if( Yii::$app->request->post() && Yii::$app->request->isPjax ) {
$query = new \yii\db\Query();
$rows = $query->select([])
->from('task')
->where('date(start) <= date(\'' . $this->request->getBodyParam('start_date') . '\')')
->all();
$items = ArrayHelper::map($rows,'id','name');
$model->setItems($items);
// Alert widget renders a message from session flash.
// Yii::$app->session->setFlash('info', "Ok....");
return $this->renderAjax('_form',[ // Or renderPartial
'partial' => true,
'model' => $model
]);
}
// else if ($this->request->isPost) {
// ..unnecessary code..
return $this->render('create', [
'model' => $model,
]);
}
}
view
// submitEvent: The jQuery event that will trigger form handler. Defaults to "submit".
<?php Pjax::begin(['submitEvent' => 'change']); ?>
<?php $form = ActiveForm::begin([
'options' => ['data-pjax' => ''],
]);
// if(hasFlash ....){ // If used ...
// Yii::$app->session->getFlash('info')
// }
?>
<?= $form->field($model, 'start')->widget......
<?= $form->field($model, 'dependencies')->dropDownList(
$model->getItems(),
// ......
<?php ActiveForm::end(); ?>
<?php Pjax::end(); ?>
Tip: The above codes will meet your goal. But you can use the following code to change more and respond to Pjax events.
jQuery or JavaScript...
$(document).on('pjax:send', function() {
// code ... Example: $('#loading').css({"visibility":"visible"}); //show()
});
$(document).on('pjax:complete', function() {
// code ... // hide()
});
// Or use if Pjax::$submitEvent = 'submit'
// $(document).on('change', '#id', function(event) { $(this).submit(); });
If you still have problems, check the date format method in SQL and ....
Good luck.
in phalcon framework i want to populate dependent drop down category list. But i'm facing some problems in my code:
#1. On select category list -> subcategory list shows: undefined (it's not populating options with value)
#2. if database have no data console.log shows: Undefined variable: resData in my controller
#3. if select category which value is '0' its not disabling the subcategory list again
What i'm doing wrong in my code?
[Module.php]
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Volt;
$di->setShared('view', function () use ($config){
$view = new View();
$view->setViewsDir(APP_PATH . $config->appB->viewsDir);
# Register Volt Template
$view->registerEngines(array(
".volt" => function($view, $di) use ($config) {
$volt = new Volt($view, $di);
$volt->setOptions(
array(
'compiledPath' => APP_PATH . $config->appB->cacheDir,
'compiledExtension' => '.php',
'compiledSeparator' => '_',
'compileAlways' => true,
'autoescape' => false,
'stat' => true
)
);
$compiler = $volt->getCompiler();
$compiler->addFunction('strtotime','strtotime');
return $volt;
}
));
return $view;
});
[CONTROLLER]
public function entryAction()
{
$formAction = 'backend/index/insert';
$this->view->setVar('action',$formAction);
$this->view->product_title = '';
$this->view->product_price = '';
$this->view->product_keyword = '';
$this->view->product_image = '';
$this->view->product_desc = '';
$category = Categories::find();
$this->view->setVar('categories',$category);
$this->view->pick("index/entry");
}
public function getSubcategoryAction()
{
$id = $this->request->getPost('id');
$data = Subcat::findBycategory_id($id);
$resData = array();
foreach($data as $result)
{
$resData[] = array('id' => $result->id, 'category_id' => $result->category_id, 'subcategory' => $result->subcategory_name);
}
echo(json_encode($resData));
//$this->view->setVar('subcategory',$resData);
}
[ENTRY VOLT]
Category:<select name="category" id="category">
<option value="0">Choose Category ...</option>
{% for category in categories %}
<option value="{{category.id}}">{{category.categoryname}}</option>
{% endfor %}
</select><br/>
sub-Category:<select name="subcategory" id="subcategory" disabled="disabled"><option value="0">Choose Sub-Category ...</option></select>
<br/>
Products:<select name="products" id="products" disabled="disabled"><option value="0">Choose a Product ...</option></select>
<br/>
[JQUERY]
$("select[name='category']").on("change", function(e){
e.preventDefault();
var value = $(this).val();
$("select[name='subcategory']").attr("disabled", false);
$.ajax({
type: "POST",
url: "http://localhost/shopping/backend/index/getSubcategory",
data:'id='+value,
}).done(function(response){
$("#subcategory").not(":first").remove();
response = JSON.parse(response);
response.forEach(function(value){
$('#subcategory').append('<option value="'+value.id+'">'+value.subcategory+'</option>');
});
}).fail(function(){
console.log('error: Please reload page and try again!');
}).always(function(){
console.log('Complete:');
});
});
Notice that in the first lines in your controller you are disabling the views, so Volt is never processed. As you are working now, jQuery only receives JSON results, so you are appending JSON rather than Volt.
You have to choose a path: either use Volt, in which case you have to remove lines 1 in both actions and process the view with parameters, or you keep sending JSON data to jQuery and you set it up properly for processing JSON response (check this answer )
In your case, getSubcategoryAction() would look like:
public function getSubcategoryAction()
{
//$this->view->disable(); //Replaced by:
$this->view->setRenderLevel(
View::LEVEL_ACTION_VIEW
);
$id = $this->request->getPost('id');
$data = Subcat::findBycategory_id($id);
foreach($data as $result)
{
$resData[] = array('id' => $result->id, 'category_id' => $result->category_id, 'subcategory' => $result->subcategory_name);
}
$this->view->setVar('categories', $resData);
}
This is assuming that you have set Volt as your render engine in your DI and your Volt template corresponds to ../app/views/index/getSubcategory.phtml, i.e.:
<?php
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Volt;
// Register Volt as a service
$di->set(
'voltService',
function ($view, $di) {
$volt = new Volt($view, $di);
$volt->setOptions(
[
'compiledPath' => '../app/compiled-templates/',
'compiledExtension' => '.compiled',
]
);
return $volt;
}
);
// Register Volt as template engine
$di->set(
'view',
function () {
$view = new View();
$view->setViewsDir('../app/views/');
$view->registerEngines(
[
'.volt' => 'voltService',
]
);
return $view;
}
);
The Volt registration code was copied from: https://docs.phalconphp.com/en/3.4/volt Modify the directories according to your App structure.
Follow This and just update your code...
[JQuery]
$("select[name='category']").on("change", function(e){
e.preventDefault();
var value = $(this).val();
if(value === '0'){$("select[name='subcategory']").attr("disabled", true); $("select[name='products']").attr("disabled", true);}else{$("select[name='subcategory']").attr("disabled", false);}
$.ajax({
type: "POST",
url: "http://localhost/shopping/backend/index/getSubcategory",
data:'id='+value,
}).done(function(response){
$("#subcategory").find('option').not(":first").remove();
$("#products").find('option').not(":first").remove();
response = JSON.parse(response);
response.forEach(function(value){
$('#subcategory').append('<option value="'+value.id+'">'+value.subcategory+'</option>');
});
}).fail(function(){
console.log('error: Please reload page and try again!');
}).always(function(){
console.log('Complete:');
});
});
I have a view in which I have a a tag button. On the click of the button a an ajax request is sent to the given action view controller and in that action view some values are saved in the database. After that I am redirecting the view to another view.
What I have done?
My View
Set PDF
//this is the a tag button
Ajax call in same view
<?php
$url = Url::toRoute(['/ogpheader/viewsetpdf','id'=>$model->id]);
$script = <<< JS
$(document).ready(function () {
$('#myid').on('click',function(e) {
e.preventDefault();
var strValue = "";
$('input[name="selection[]"]:checked').each(function() {
if(strValue!="")
{
strValue = strValue + " , " + this.value;
}
else
strValue = this.value;
});
//alert(strValue);
$.ajax({
url: '$url',
type: 'POST',
dataType: 'json',
data: {data:strValue},
success: function(data) {
alert(data);
},
});
})
});
JS;
$this->registerJs($script, static::POS_END);
?>
My action Controller
if(Yii::$app->request->isAjax && Yii::$app->request->post())
{
$data = explode(',',$_POST['data']);
foreach($data as $value)
{
$m = new Ogpdetail;
$m -> load(Yii::$app->request->post());
$m->ogp_id = $ogp_id;
$m->created_at = date('Y-m-d h:i:s');
$m->meter_id = $value;
$m->meter_serial = \common\models\Meters::idTomsn($value);
if($m->save())
{
$model->status = Ogpheader::$status_titles[1];
$model->update();
//echo "All data is saved";
//exit();
}
else{
$this->renderAjax('viewcreated');
}
}
//print_r($data);
}
else{
$this->renderAjax('viewcreated');
}
$query = "SELECT DISTINCT ogpd.`meter_serial` AS 'Meter_Serial_Number', IFNULL(ogpd.`remarks`,'') AS 'Remarks' FROM `ogp_detail` ogpd
INNER JOIN `ogp_header` ogph ON ogpd.`ogp_id` = ogph.`id`";
$count = Yii::$app->db->createCommand("SELECT COUNT(DISTINCT ogpd.`meter_serial`) FROM `ogp_detail` ogpd
INNER JOIN `ogp_header` ogph ON ogpd.`ogp_id` = ogph.`id`")->queryScalar();
$dataProvider = new SqlDataProvider([
'sql' => $query,
'totalCount' => $count,
'pagination' => [
'pageSize' => 5,
],
]);
return $this->redirect('viewsetpdf',[
'dataProvider' => $dataProvider,
'model' => $this->findModel($id),
'id' => $model->id
]);
When i click on my Set PDF button I am getting Not Found (#404). While all the records are saved into my desired tables.
Also the URL is http://localhost:225/inventory-web/backend/web/ogpheader/viewcreated/viewsetpdf but it should be http://localhost:225/inventory-web/backend/web/ogpheader/viewsetpdf
I don't know what is the problem and I am stuck to it.
Any help would be highly appreciated.
You are generating a Route, not a URL. Try replacing this:
Set PDF
With this:
Html::a('Set PDF', ['ogpheader/viewsetpdf', 'id'=>$model->id], ['id' => 'myid', 'name'=>'redirect', 'class'='btn btn-primary'])
I am using kartik select2 widget in my yii2 basic app. now i have to display province names in select2 widget on ajax call. It is working fine if i put it directly in form. however not working with ajax call.
Here are my form fields:
<?= $form->field($model, 'role')->dropDownList(
ArrayHelper::map(SubAdminRoles::find()->all(), 'id', 'role_name'),
[
'prompt' => 'Select Role',
'onchange' => '
if($(this).val() != 3) {
$( "#user_area" ).html("showLoading");
$.post( "fetch-area-list?id='.'"+$(this).val(),
function(data) {
$( "#user_area" ).html(data);
})
}'
]
) ?>
<div id="user_area">
</div>
And here is my action code
public function actionFetchAreaList($id) {
// $this->layout = 'none';
$data = [];
if($id == 1) {
$provinceList = \app\modules\adminpanel\models\ProvinceMaster::findAll(['status' => 1, 'is_deleted' => 0]);
foreach($provinceList as $obj) {
$data[$obj['id']] = $obj['province_name'];
}
//print_r($data);
//exit;
} else if($id == 2) {
$subDistrictList = \app\modules\adminpanel\models\SubDistrictMaster::findAll(['status' => 1, 'is_deleted' => 0]);
foreach($subDistrictList as $obj) {
$data[$obj['id']] = $obj['sub_district_name'];
}
}
echo '<label class="control-label">Select Province</label>';
echo Select2::widget([
'name' => 'state_2',
'value' => '1',
'data' => $data,
'options' => ['multiple' => true, 'placeholder' => 'Select Province']
]);
exit;
}
now when i try to get it through ajax i comes with display:none property so i am not able to show my select2 box.
I Also tried changing display:none to display:block in select2 class. In that case i got the select box, but is simple html multiple select box not select2 widget.
How to get it from controller using ajax call?
Thanks in advance.
It is bad practice to render html inside action.
In your case widget requires related JS for initialization. But it will not include in your response.
Move all your html to view area-list and render using following code:
public function actionFetchAreaList($id) {
$this->layout = false;
// ... preparing data
return $this->renderAjax('area-list', [
// ... some view data
]);
}
Method renderAjax renders a named view and injects all registered JS/CSS scripts and files. It is usually used in response to AJAX Web requests.
I also have similar project like this.
I have 2 combobox (using select2). When select a district from the first combobox. It will call an ajax request to get province list and fill into the second combobox.
Here is my solution:
Using Select2 widget as normally in form
Using javascript to call ajax request and change data of the second combobox.
My controller response data in json format.
$('#district-selector').on('change', function() {
var districtId = $(this).val();
var url = $(this).attr('tb_href');
$('#province-selector').html('');
$.get(
url,
{
city_id: districtId
},
function(response) {
if (response.error == 0 && response.data.length) {
$('#province-selector').append(new Option('', ''));
$.each(response.data, function() {
console.log(this.id + '--' + this.title);
var newOption = new Option(this.title, this.id);
$('#province-selector').append(newOption);
});
}
$('#province-selector').trigger('change');
}
);
});
Demo: demo link
My ajax function for saving post is making multiple requests, and i can't understand why. I tried searching for the duplicate elements, that may cause double clicking, but there is no duplicates. And sometimes it posts on ONE click 4 times
Here is the screenshot of multiple ajax post, when i click on #order_save button,
My #order_save button, when i search for the order_save in the DOM tree, the first match is this element. (original click element)
And the second match(2 of 2) for the order_save is at jquery code (which is normal)
jQuery(function($) {
$(document).on('click','#order_save',function(){
var order_title = $('#client-order-title').val();
var order_comment = $('#client-comment').val();
var order_date = $('#order_date_till').val();
var price_input = $('#order_price').val();
var order_price;
var order_attachments = [];
if($('#order_price_on_deal:checked').val() == 'foo') {
order_price = 'foo';
}else{
order_price = price_input;
}
if(!order_title) {
$('#client-order-title').addClass('has-error');
return false;
}else{
$('#client-order-title').removeClass('has-error');
}
if(!order_comment) {
$('#client-comment').addClass('has-error');
return false;
}else{
$('#client-comment').removeClass('has-error');
}
$('#files_public .order-attachment').each(function() {
var attachment_link = $(this).find('a').attr('href');
var attachment_title = $(this).text();
order_attachments.push({
'file_url' : attachment_link,
'file_name' : attachment_title
});
});
$.ajax({ // Line 68 is here
url: my_ajax.url,
type: "POST",
data: {
'action' : 'xx_order_saving',
'order_title' : order_title,
'order_comment' : order_comment,
'order_date' : order_date,
'order_price' : order_price,
'order_attachment' : order_attachments,
'order_type' : 'public_order'
},
dataType: "json",
success: function(response){
if(response.html) {
$('#currentOrder').html(response.html);
}
}
})
});
});
PHP handler in my functions php (working fine)
function xx_order_saving() {
// posting data here
if($order_title && $order_comment) {
$new_post_a = array(
'post_type' => 'orders',
'post_title' => $order_title,
'post_status' => 'publish'
);
$new_order = wp_insert_post($new_post_a);
if($new_order) {
wp_update_post( array( 'ID' => $new_order, 'post_name' => $new_order ) );
}
$template_file = 'xxx-order-saved.php';
ob_start();
include(locate_template($template_file,false,false));
$page_template = ob_get_contents();
ob_end_clean();
$response['html'] = $page_template;
wp_send_json($response);
}
}
add_action('wp_ajax_xx_order_saving','xx_order_saving');
add_action('wp_ajax_nopriv_xx_order_saving','xx_order_saving');
The template file with the jquery code above is loaded dynamically using this function
function load_frame() {
$option = $_POST['option'];
if($option){
$template_file = 'xxxx-'.$option.'.php';
ob_start();
include(locate_template($template_file,false,false));
$page_template = ob_get_contents();
ob_end_clean();
$response['html'] = $page_template;
wp_send_json($response);
}
}
Sometimes it works just fine, sending one request, saving one post, sometimes it posts 4 or 2 times as shown in the screenshot above.
Here is what seems to cause the problem:
If there is order-attachments, for example one attachment it will send two requests (save two posts) if there is two attachments it will send One request, if there is three attachments it will send 4 requests, if there is 5 it sending One again. I just don't get it. Any help will be appreciated
<div id="files_public" class="form-group">
<span class="list-group-item order-attachment">Image.png
...</span>
</div>
Change
$(document).on("click", "#order_save", function () {
to
$("#order_save").click(function () {