I would like to iterate and edit data from a pivot table in edit.ctp.
Displaying and editing one entity works fine with the code below (if there is at least one entry):
edit.ctp
echo $this->Form->control('winkels.0._joinData.winkel_id', [
'options' => $winkels,
'label' => 'Winkel',
'type' => 'select'
]);
echo $this->Form->control('winkels.0._joinData.url');
echo $this->Form->control('winkels.0._joinData.prijs');
I could get the depth of the array and change the index of winkels, but that's just dirty... I am not even sure if that would work.
So I tried the code below but it does not create the right HTML:
if(!empty($product->winkels)) {
foreach ($product->winkels as $winkel) {
echo $this->Form->control($winkel->_joinData->winkel_id, [
'options' => $winkels,
'label' => 'Winkel',
'type' => 'select'
]);
echo $this->Form->control($winkel->_joinData->url, [
'label' => 'URL',
'value' => $winkel->_joinData->url
]);
echo $this->Form->control($winkel->_joinData->prijs, [
'label' => 'Prijs',
'value' => $winkel->_joinData->prijs
]);
}
}
Is there a clean way the generate these controls for the pivot table? Also if $product->winkels is empty, how do I make the first entry?
Additional info:
--- EDIT ---
I have adjusted my code, but I seems that it fails to create the "pivoting table"
if(!empty($product->winkels)) {
foreach ($product->winkels as $index => $winkel) {
echo $this->Form->control('winkels.$index.winkel_id');
echo $this->Form->control('winkels.$index._joinData.winkel_id', [
'options' => $winkels,
'label' => 'Winkel',
'type' => 'select'
]);
echo $this->Form->control('winkels.$index.url', [
'value' => $winkel->_joinData->url]
);
echo $this->Form->control('winkels.$index.prijs', [
'value' => $winkel->_joinData->prijs]
);
}
} else {
echo $this->Form->control('winkels.0.winkel_id');
echo $this->Form->control('winkels.0._joinData.winkel_id', [
'options' => $winkels,
'label' => 'Winkel',
'type' => 'select'
]);
echo $this->Form->control('winkels.0._joinData.url');
echo $this->Form->control('winkels.0._joinData.prijs');
}
As you can see in the debug result, a lot of the structure is missing:
There's nothing dirty about using the array's index, that's actually exactly how you'd do it, ie something along the lines of:
foreach ($product->winkels as $index => $winkel) {
echo $this->Form->control("winkels.$index.id");
echo $this->Form->control("winkels.$index._joinData.winkel_id", [/* ... */]);
echo $this->Form->control("winkels.$index._joinData.url", [/* ... */]);
echo $this->Form->control("winkels.$index._joinData.prijs", [/* ... */]);
}
Also don't forget the primary key if you want to update existing records! And note that you don't need to provide the value, the form helper will find the value itself based on the given field name.
And if winkels is empty, then you simply start with the index 0, just like in your first example.
See also
Cookbook > Views > Helpers > Form > Creating Inputs for Associated Data
Related
I'm new to TYPO3 (first project) and I have some understanding issues of the creation of a custom element with a colorpicker. In this project I already have created a few elements but I only use predetermined fields for the backend input. For the element I need next I need the user to choose a color. I haven't found a fitting existing element. My setup that doesn't work is in the TCA/Overrides/tt_content.php file and looks like this.
$GLOBALS['TCA']['tt_content']['item_0']=array();
$GLOBALS['TCA']['tt_content']['item_0']['label']='Color';
$GLOBALS['TCA']['tt_content']['item_0']['config']=array();
$GLOBALS['TCA']['tt_content']['item_0']['config']['type']='input';
$GLOBALS['TCA']['tt_content']['item_0']['config']['renderType']='colorpicker';
$GLOBALS['TCA']['tt_content']['item_0']['config']['size']=10;
$GLOBALS['TCA']['tt_content']['types']['wo_mitem'] = array(
'showitem' => '--palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
header;Title,
subheader;Background,
header_link;Target,
item_0;Color,
bodytext;Text;;richtext:rte_transform[flag=rte_enabled|mode=ts_css]
');
The item_0 was a try to create a colorpicker but it doesn't seem to work. Do I need something different in a different file? The first few lines I added to define my field. Is there a better way to do this?
All other files in my custom extension work (since all other custom elements work fine). The only difference is, as said, the need of a way to choose a color in the new one.
Just for a clearer look here the other files
setup.txt:
lib.contentElement {
templateRootPaths {
100 = EXT:wostyle/Resources/Private/Template
}
}
tt_content {
wo_mitem < lib.contentElement
wo_mitem {
templateName = MItem
}
}
tt_content.php
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPlugin(
array(
'WO_Item (ItemBox, Text only)',
'wo_mitem',
'content-image'
),
'CType',
'wostyle'
);
$GLOBALS['TCA']['tt_content']['item_0']=array();
$GLOBALS['TCA']['tt_content']['item_0']['label']='Farbe';
$GLOBALS['TCA']['tt_content']['item_0']['config']=array();
$GLOBALS['TCA']['tt_content']['item_0']['config']['type']='input';
$GLOBALS['TCA']['tt_content']['item_0']['config']['renderType']='colorpicker';
$GLOBALS['TCA']['tt_content']['item_0']['config']['size']=10;
$GLOBALS['TCA']['tt_content']['types']['wo_mitem'] = array(
'showitem' => '--palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
header;Bezeichnung,
subheader;Chemische Bezeichnung,
header_link;Zielseite,
item_0;Farbe,
bodytext;Text;;richtext:rte_transform[flag=rte_enabled|mode=ts_css]
');
typo.ts
mod.wizards.newContentElement.wizardItems.wo_extra {
header = WO Elemente
after = common
elements {
wo_mitem {
iconIdentifier = content-image
title = WO_Item (ItemBox, Text only)
description = Ein Produktfeld mit Text
tt_content_defValues {
CType = wo_mitem
}
}
}
show := addToList(wo_mitem)
}
MItem.html
<div class="item-text">
<f:link.typolink parameter="{data.header_link}">
<div class="item-front">
<f:if condition="{data.subheader}!=''">
<f:then>
<div class="item-bg">
<f:format.html>{data.subheader}</f:format.html>
</div>
</f:then>
</f:if>
<div class="item-title">
<f:format.html>{data.header}</f:format.html>
</div>
</div>
<div class="item-back">
<f:format.html>{data.bodytext}</f:format.html>
</div>
</f:link.typolink>
</div>
<f:debug>{data}</f:debug>
EDIT: I use typo3 8.7.8
I did not check your whole code but I have a working color-picker on a field ...
you're close but an error that pops up right away is that your item should be placed under ['columns'] ...
$GLOBALS['TCA']['tt_content']['columns']['item_0']=array();
next you are missing the refference to the wizard !! (you should adopt the annotation with square brackets which shows much more the structure)
this should be stored in Configuration/TCA/Overrides/tt_content.php: (when you override existing fields, otherwise you have a dedicated code for the element)
<?php
/***************
* Modify the tt_content TCA
*/
$tca = [
'columns' => [
'item_0' => [
'label' => 'Color',
'config' => [
'type' => 'input',
'size' => 10,
'eval' => 'trim',
'default' => '#ffffff',
'wizards' => [
'colorChoice' => [
'type' => 'colorbox',
'title' => 'LLL:EXT:lang/locallang_wizards:colorpicker_title',
'module' => [
'name' => 'wizard_colorpicker'
],
'dim' => '20x20',
'JSopenParams' => 'height=600,width=380,status=0,menubar=0,scrollbars=1',
],
],
],
],
],
];
$GLOBALS['TCA']['tt_content'] = array_replace_recursive($GLOBALS['TCA']['tt_content'], $tca);
With the help of webMan and some internet searches I could adopt my code a little.
I added the file "ext_tables.sql" with the content
CREATE TABLE tt_content (
item_0 varchar(10) DEFAULT '' NOT NULL,
);
And changed the tt_content.php in TCA/Overrides to:
$temporaryColumns = Array(
"item_0" => Array(
'label' => 'Color',
'config' => Array(
'type' => 'input',
'renderType' => 'colorpicker',
'size' => 10
)
)
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('tt_content',$temporaryColumns);
$GLOBALS['TCA']['tt_content']['types']['wo_mitem'] = array(
'showitem' => '--palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
header;Bezeichnung,
subheader;Chemische Bezeichnung,
header_link;Zielseite,
item_0;Farbe,
bodytext;Text;;richtext:rte_transform[flag=rte_enabled|mode=ts_css]
');
There are still a view things missing in compare to webMans code but at least this is the first working version I have so i figured i show it since my question is answered:).
I have translates table with example data:
So, this table holds records, which will represent custom translation texts.
Now i want to build a form to edit all of those rows in one page / form.
This is controlle code:
public function translate() {
$this->loadModel('Translate');
$data = $this->Translate->find('all');
$this->set('data', $data);
pr ($this->request->data);
if ($this->request->is('post','put')) {
if ($this->Translate->save($this->request->data)) {
$this->Session->setFlash('Recipe Saved!');
return $this->redirect($this->referer());
}
}
}
And view - please note, that i have used loop for creating inputs, not sure if cakephp has better way to do this.
<?php echo $this->Form->create('Translate'); ?>
<?php
foreach ($data as $d) {
echo $this->Form->input('text', array('label' => 'Link strony', 'type' => 'text','value'=>$d['Translate']['text']));
echo $this->Form->input('id', array('type' => 'hidden', 'value' => $d['Translate']['id']));
}
?>
<?php echo $this->Form->end(array('class' => 'btn btn-success floatRight', 'label' => 'Zapisz')); ?>
For now, this code works, but not as i expect. $this->request->data shows only last input, ignoring other ones. Attached, you see debug of $this->request->data. Only last item is edited. All i want is to have ability to edit selected input and save. Thanks for help.
Looks like you're saving multiple rows in a single form. In that case,
you need to change your approach a bit.
Use proper indices in the Form helper.
Use saveAll() instead of save() to save multiple data.
Changes to the View file:
<?php
foreach ($data as $k => $d) {
echo $this->Form->input('Translate.'.$k.'.text', array(
'label' => 'Link strony',
'type' => 'text',
'value' =>$d['Translate']['text']
));
echo $this->Form->input('Translate.'.$k.'.id', array(
'type' => 'hidden',
'value' => $d['Translate']['id']
));
}
?>
And then, in your controller:
if ($this->request->is('post','put')) {
$this->Translate->saveAll($this->request->data['Translate']);
/* Other code */
}
Try to specify the name as array (translate[]) :
echo $this->Form->input('text', array('label' => 'Link strony', 'type' => 'text','value'=>$d['Translate']['text'],'name'=>'translate[]'));
I want to make search in my project. I use typeahead but it's not working. This is my code:
<?php
echo '<label class="control-label">Select Repository</label>';
$template = '<div><p class="repo-language">{{no_telepon}}</p>' .
'<p class="repo-name">{{nama}}</p>' .
'<p class="repo-description">{{email}}</p></div>';
echo Typeahead::widget([
'name' => 'twitter_oss',
'options' => ['placeholder' => 'Filter as you type ...'],
'dataset' => [
[
'prefetch' => Penerima::find()->all(),
'datumTokenizer' => "Bloodhound.tokenizers.obj.whitespace('value')",
'display' => 'value',
'templates' => [
'notFound' => '<div class="text-danger" style="padding:0 8px">Unable to find repositories for selected query.</div>',
'suggestion' => new JsExpression("Handlebars.compile('{$template}')")
]
]
]
]);
?>
This question was asked long time a go.
I also faced the same problem, but i could figure-out this.
for future reference i add this post.
in your controller
$result = SampleModel::find()
->select('Attribute_name')
->where('name LIKE "%' . $searchParameter .'%"')
->asArray()
->all();
return Json::encode($result);
here you need to get the database value as "associative array", you can get that from using "asArray()".
then as you see return value as Json encode.
in your "View"
<?php
echo Typeahead::widget([
'name' => 'sampleName',
'options' => ['placeholder' => 'Filtering data ...'],
'scrollable' => true,
'pluginOptions' => ['highlight'=>true],
'dataset' => [
[
'remote' => [
'url' => Yii::$app->urlManager->createUrl(['sample/action']) .
'?searchParameter=%QUERY',
'wildcard' => '%QUERY'
],
'datumTokenizer' => "Bloodhound.tokenizers.obj.whitespace('Atribute_name')",
'display' => 'Atribute_name',
'limit' => 10,
],
],
'pluginEvents' => [
'typeahead:select' => 'function(e, s) {
EnableUserDetailsTypeAhead(s);
}',
]
]);
?>
here few things to be consider.
calling to the controller action. you can do that.
Yii::$app->urlManager->createUrl(['sample/action']) .
'?searchParameter=%QUERY',
'wildcard' => '%QUERY'
],
the below lines inside data set must be provide.
'datumTokenizer' => "Bloodhound.tokenizers.obj.whitespace('Atribute_name')",
'display' => 'Atribute_name',
you will get the expected data.
this sample code i have tested and this is working
From the docs:
prefetch: array, configuration for the prefetch options object. Refer documentation for the options you can set for this parameter. The return data must be Json encoded and converted to an associative array of the format [['value' => 'data1'], ['value' => 'data2'],...], where value is the fixed key set in display
You are passing an array of objects instead of an array of key value pairs. You can use asArray to create a list of objects. You will need to change display to the name of the field containing the data:
'prefetch' => Penerima::find()->select('title')->asArray()->all(),
I'm a beginner in writing PHP, but working on developing themes in WordPress.
I have no idea how to echo my style option within my front-page.php.
My meta.php:
$meta_style = array();
$meta_style['meta_style'] = array(
'dash_icon' => 'list-view',
'title' => __('Section Settings', 'fluent'),
'description' => __('These are general section settings.','fluent'),
'context' => 'normal',
'priority' => 'high',
'option_name' => 'meta_style',
'caps' => array(),
'fields' => array(
'style' => array(
//...
'type' => 'select',
'options' => array(//option value = option label
'value' => 'white',
'value2' => 'black'
),
'multiple' => false,//allow multiple values to be selected - default false
'placeholder' => 'white'//placeholder text for the element
),
),
);
My front-page.php (it's wrapped in a BUTTON just a see if the variable echoes):
<button>
<? if($meta = get_post_meta($post->ID)){ if($meta['style'] == true){ echo $meta['value']; } } ?>
</button>
Can anyone provide an additional examples on how to echo other types, such as 'type' => 'text'?
I dont know exactly what you want, but you should:
1 - See if you're echoing the right information
2 - Use var_dump()
In your first code example you have a variable $meta_style which is a map. It has one key, 'meta_style' that leads to a next map. Inside that inner map you have the keys 'dash_icon' and so on. So for example this should echo the string 'normal':
echo $meta_style['meta_style']['context'];
However, in your second example, you have a variable $meta which is also a map, having keys 'style' and 'value'. You could echo those with:
echo $meta['style'];
echo $meta['value'];
Based on your example, I have no idea what these should do or how they should be related, or what their meaning should be.
I have a gridview which contains a checkbox column and also uses pagination. When I check some checkboxes in the first page and navigate to the second page and check another one in the second page, the options I checked in the first page is not retained there. Is it posssible to retain the checkbox values during pagination?
Code for Gridview is
$widget = $this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => $model->search(),
'cssFile' => Yii::app()->baseUrl . '/media/js/admin/css/admingridview.css',
//'filter' => $model,
'ajaxUpdate' => true,
'enablePagination' => true,
'columns' => array(
array(
'name' => 'id',
'header' => '#',
'value' => '$this->grid->dataProvider->pagination->currentPage * $this->grid->dataProvider->pagination->pageSize + ($row+1)',
),
array(
'class' => 'CCheckBoxColumn',
'selectableRows' => '2',
'header' => 'Selected',
),
array(
'name' => 'fb_user_id',
'header' => 'FaceBook Id',
'value' => 'CHtml::encode($data->fb_user_id)',
),
array(
'name' => 'first_name',
'header' => 'Name',
'value' => 'CHtml::encode($data->first_name)',
),
array(
'name' => 'email_id',
'header' => 'Email',
'value' => 'CHtml::encode($data->email_id)',
),
array(
'name' => 'demo',
'type' => 'raw',
'header' => "Select",
'value' => 'CHtml::checkBox("email[]","",array("class"=>"check","value"=>$data->email_id))',
),
),
));
Edit:
Extension for remembering the selected options in gridview,check this link Selgridview
Thanks to bool.dev
You could use sessions/cookies to store the checked values. I'm not very sure how to make cookies work, so i'll tell you how to do it with sessions. Specifically the user session that yii creates.
Now to use sessions we need to pass the checked (and unchecked) ids to the controller, therefore we'll modify the data being sent to the controller on every ajax update(i.e between paginations), to do this we exploit the beforeAjaxUpdate option of CGridView.
I'm also using CCheckBoxColumn instead of the following in your code(of course you can modify the solution to suit your own needs):
array(
'name' => 'demo',
'type'=>'raw',
'header' => "Select",
'value' => 'CHtml::checkBox("email[]","",array("class"=>"check","value"=>$data->email_id))',
),
GridView Changes:
<?php $this->widget('zii.widgets.grid.CGridView', array(
// added id of grid-view for use with $.fn.yiiGridView.getChecked(containerID,columnID)
'id'=>'first-grid',
'dataProvider'=>$model->search(),
'cssFile' => Yii::app()->baseUrl . '/media/js/admin/css/admingridview.css',
// added this piece of code
'beforeAjaxUpdate'=>'function(id,options){options.data={checkedIds:$.fn.yiiGridView.getChecked("first-grid","someChecks").toString(),
uncheckedIds:getUncheckeds()};
return true;}',
'ajaxUpdate'=>true,
'enablePagination' => true,
'columns' => array(
array(
'name' => 'id',
'header' => '#',
'value' => '$this->grid->dataProvider->pagination->currentPage * $this->grid->dataProvider->pagination->pageSize + ($row+1)',
),
array(
'name' => 'fb_user_id',
'header' => 'FaceBook Id',
'value' => 'CHtml::encode($data->fb_user_id)',
),
array(
'name' => 'first_name',
'header' => 'Name',
'value' => 'CHtml::encode($data->first_name)',
),
array(
'name' => 'email_id',
'header' => 'Email',
'value' => 'CHtml::encode($data->email_id)',
),
/* replaced the following with CCheckBoxColumn
array(
'name' => 'demo',
'type'=>'raw',
'header' => "Select",
'value' =>'CHtml::checkBox("email[]","",array("class"=>"check","value"=>$data->email_id))',
),
*/
array(
'class' => 'CCheckBoxColumn',
'selectableRows' => '2',
'header'=>'Selected',
'id'=>'someChecks', // need this id for use with $.fn.yiiGridView.getChecked(containerID,columnID)
'checked'=>'Yii::app()->user->getState($data->email_id)', // we are using the user session variable to store the checked row values, also considering here that email_ids are unique for your app, it would be best to use any field that is unique in the table
),
),
));
?>
Pay special attention to the code for beforeAjaxUpdate and CCheckBoxColumn, in beforeAjaxUpdate we are passing checkedIds as a csv string of all the ids(in this case email_ids) that have been checked and uncheckedIds as a csv string of all the unchecked ids, we get the unchecked boxes by calling a function getUncheckeds(), which follows shortly. Please take note here, that when i was testing i had used an integer id field (of my table) as the unique field, and not an email field.
The getUncheckeds() function can be registered like this anywhere in the view file for gridview:
Yii::app()->clientScript->registerScript('getUnchecked', "
function getUncheckeds(){
var unch = [];
/*corrected typo: $('[name^=someChec]') => $('[name^=someChecks]') */
$('[name^=someChecks]').not(':checked,[name$=all]').each(function(){unch.push($(this).val());});
return unch.toString();
}
"
);
In the above function pay attention to the selectors and each and push function.
With that done, we need to modify the controller/action for this view.
public function actionShowGrid(){
// some code already existing
// additional code follows
if(isset($_GET['checkedIds'])){
$chkArray=explode(",", $_GET['checkedIds']);
foreach ($chkArray as $arow){
Yii::app()->user->setState($arow,1);
}
}
if(isset($_GET['uncheckedIds'])){
$unchkArray=explode(",", $_GET['uncheckedIds']);
foreach ($unchkArray as $arownon){
Yii::app()->user->setState($arownon,0);
}
}
// rest of the code namely render()
}
That's it, it should work now.
For developing that scheme you would need to know working of what happens when you navigate.
When ever you navigate to a pagination page ajax calls are made and new data is received and it is fetched from CActive Record or what ever the data source. New data is in accordance of database records or source records. when you come back to previous page again Ajax call is made and content is updated so same comes as it is in database.
what i feel is you should save data of checked items temporary and make it permanent if action is made.
You can do something like this
<script type="text/javascript">
$("input:checkbox").click(function () {
var thisCheck = $(this);
if (thisCheck.is (':checked')){
// do what you want here, the way to access the text is using the
// $(this) selector. The following code would output pop up message with
// the selected checkbox text
$(this).val());
}
});
</script>
you can save temporary storage somewhere
Also make this work on normal form submit:
I wanted to add this as a comment on bool.dev's answer, but I do not have enough reputation to do that yet. So I had to put it in a separate answer.
bool.dev, your answer is great and it works well, thanx.
However, as intended, it only works when ajax calls update the gridview. I have the gridview forming part of a form, so I wanted it to also work on normal submission of the form, otherwise the checkboxes are not loaded again when there are other validation errors on the form.
So, in ADDITION to what you did, I added hidden fields on my form e.g.:
<input type="hidden" name='checkedBox1' id='checkedBox1' value=''>
<input type="hidden" name='uncheckedBox1' id='uncheckedBox1' value=''>
Then, before submitting the form, my sumbit button runs your getChecked() and getUncheckeds() functions and store their results in the hidden fields:
if ($('#checkedBox1').length >0) {$('[name=checkedBox1]').val(getChecked());}
if ($('#uncheckedBox1').length >0) {$('[name=uncheckedBox1]').val(getUncheckeds());}
In the controller, besides from checking for $_GET['checkedIds'], you also check for $_POST['checkedBox1'] and store its values to session in the same way you do for $_GET['checkedIds'], using the same session variable.
Do the same with $_POST['uncheckedBox1'].
That should work.