Is it possible to disable a field in the TCA config, only when editing a record?
TCA config for new record:
'title' => [
'exclude' => true,
'label' => 'Title',
'config' => [
'type' => 'input',
'size' => 30,
'eval' => 'trim,required'
],
],
TCA config for existing records:
'title' => [
'exclude' => true,
'label' => 'Title',
'config' => [
'type' => 'input',
'size' => 30,
'eval' => 'trim,required'
'readOnly' => true,
],
],
I'm not aware of a built in solution for different TCA settings for new and existing records.
Since the final TCA is cached there is also no way to manipulate it with some PHP on runtime.
It is possible to add Javascript in the backend. With this Javascript your are able, to disable fields on the fly. But be aware, that this is just a hacky workaround which can easily be overcome!
Add Javascript in ext_localconf.php:
if (TYPO3_MODE === 'BE') {
$renderer = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Page\PageRenderer::class);
$renderer->addJsFile(
'EXT:myext/Resources/Public/JavaScript/Backend.js'
);
}
In Backend.js you can do something like this:
require(["jquery"], function ($) {
const queryString = decodeURI(window.location.search),
urlParams = new URLSearchParams(queryString);
if (urlParams.has('route') && urlParams.get('route') == '/record/edit') {
// check, that you just do changes, if you edit records of the desired model
if (queryString.indexOf('edit[tx_myextension_domain_model_model][')) {
let idPosStart = queryString.indexOf('edit[tx_myextension_domain_model_model][') + 40,
idPosEnd = queryString.indexOf(']=', idPosStart),
idLength = idPosEnd - idPosStart,
idEl = queryString.substr(idPosStart, idLength),
elVal = urlParams.get('edit[tx_myextension_domain_model_model][' + idEl + ']');
if (elVal == 'edit') {
// Delay everything a little bit, otherwise html is not fully loaded and can't be addressed
setTimeout(function () {
// disable desired fields, eg field "title"
let titleField = $('[data-field="title"]').parents('.form-section');
titleField.find('input').prop('disabled', true);
titleField.find('button.close').remove();
}, 800);
}
}
}
}
Related
Whenever I submit the form I get this message:
The input was not found in the haystack.
This is for the shipping-method element (radio button). Can't figure out what it means, the POST data for that element is not null.
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
// Some other basic filters
$inputFilter->add(array(
'name' => 'shipping-method',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim')
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'max' => 20,
),
),
array(
'name' => 'Db\RecordExists',
'options' => array(
'table' => 'shipping',
'field' => 'shipping_method',
'adapter' => $this->dbAdapter
)
),
),
));
$inputFilter->get('shipping-address-2')->setRequired(false);
$inputFilter->get('shipping-address-3')->setRequired(false);
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
I only keep finding solutions for <select>.
Here's the sample POST data:
object(Zend\Stdlib\Parameters)#143 (1) {
["storage":"ArrayObject":private] => array(9) {
["shipping-name"] => string(4) "TEST"
["shipping-address-1"] => string(4) "test"
["shipping-address-2"] => string(0) ""
["shipping-address-3"] => string(0) ""
["shipping-city"] => string(4) "TEST"
["shipping-state"] => string(4) "TEST"
["shipping-country"] => string(4) "TEST"
["shipping-method"] => string(6) "Ground"
["submit-cart-shipping"] => string(0) ""
}
}
UPDATE:
form.phtml
<div class="form-group">
<?= $this->formRow($form->get('shipping-method')); ?>
<?= $this->formRadio($form->get('shipping-method')
->setValueOptions(array(
'Ground' => 'Ground',
'Expedited' => 'Expedited'))
->setDisableInArrayValidator(true)); ?>
</div>
ShippingForm.php
$this->add(array(
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => array(
'label' => 'Shipping Method',
'label_attributes' => array(
'class' => 'lbl-shipping-method'
),
)
));
The problem lies with when you use the setValueOptions() and the setDisableInArrayValidator(). You should do this earlier within your code as it is never set before validating your form and so the inputfilter still contain the defaults as the InArray validator. As after validation, which checks the inputfilter, you set different options for the shipping_methods.
You should move the setValueOptions() and the setDisableInArrayValidator() before the $form->isValid(). Either by setting the right options within the form itsself or doing this in the controller. Best way is to keep all of the options in one place and doing it inside the form class.
$this->add([
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => [
'value_options' => [
'Ground' => 'Ground',
'Expedited' => 'Expedited'
],
'disable_inarray_validator' => true,
'label' => 'Shipping Method',
'label_attributes' => [
'class' => 'lbl-shipping-method',
],
],
]);
Another small detail you might want to change is setting the value options. They are now hardcoded but your inputfilter is checking against database records whether they exist or not. Populate the value options with the database records. If the code still contains old methods but the database has a few new ones, they are not in sync.
class ShippingForm extends Form
{
private $dbAdapter;
public function __construct(AdapterInterface $dbAdapter, $name = 'shipping-form', $options = [])
{
parent::__construct($name, $options)
// inject the databaseAdapter into your form
$this->dbAdapter = $dbAdapter;
}
public function init()
{
// adding form elements to the form
// we use the init method to add form elements as from this point
// we also have access to custom form elements which the constructor doesn't
$this->add([
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => [
'value_options' => $this->getDbValueOptions(),
'disable_inarray_validator' => true,
'label' => 'Shipping Method',
'label_attributes' => [
'class' => 'lbl-shipping-method',
],
],
]);
}
private function getDbValueOptions()
{
$statement = $this->dbAdapter->query('SELECT shipping_method FROM shipping');
$rows = $statement->execute();
$valueOptions = [];
foreach ($rows as $row) {
$valueOptions[$row['shipping_method']] = $row['shipping_method'];
}
return $valueOptions;
}
}
Just had this happen yesterday.
The select and multi select ZF2+ elements have a built in in_array validator.
Remember filters occur before validators.
You may be doing too much here -- it is very rare to need to filter or add validators ot select and multi select form elements in ZF2 forms. The built in element validator is robust, ZF does a lot of work for us.
Try removing both filter and validator for the element, such as:
$inputFilter->add(array(
'name' => 'shipping-method',
'required' => true,
));
There is another edge case that I have seen: changing the select element's valueOptions somewhere in the controller (or view) resulting in different valueOptions used in view vs form validation (in our case it was replacing the element with a new one before validation).
I think your problem lies in the fact you are adding your value options after the InArray validator has been set, hence the validator has no haystack.
Try this
$this->add(array(
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => array(
'label' => 'Shipping Method',
'label_attributes' => array(
'class' => 'lbl-shipping-method'
),
'value_options' => array(
'Ground' => 'Ground',
'Expedited' => 'Expedited'
),
'disable_inarray_validator' => TRUE,
)
));
and remove setValueOptions and setDisableInArrayValidator from your view.
Hope this works.
I have two fileds, that are uses two different instances of the same model class.
Test Case Video
$form->field($billing_address, 'zip',
[
'selectors' => [
'input' => '#billing-zip',
'container' => '#billing-container',
],
'options' => ['id' => 'billing-container'],
])->textInput(['maxlength' => 11,
'name'=> 'Billing_Address[zip]',
'id'=>'billing-zip']);
//Shipping
$form->field($shipping_address, 'zip',
[
'selectors' => [
'input' => '#shipping-zip',
'container' => '#shipping-container',
],
'options' => ['id' => 'shipping-container'],
])->textInput(['maxlength' => 11,
'name'=> 'Shipping_Address[zip]',
'id'=>'shipping-zip']);
When I finish filling fields, errors are shown for only fields that has errors.
But when I push submit, if one of zip fields has errors, error appears for all zip fields
public function rules()
{
return [
[['zip'], 'string', 'max' => 23],
];
}
I think you can use something like this in your controller:
if( Model::loadMultiple($model_array, Yii::$app->request->post()) && Model::validateMultiple($model_array) && $model->validate()){
//your stuff
}
where $model_array are an array of models
$model_array['model1'] = new YourModelClass();
$model_array['model2'] = new YourModelClass();
Documentation
'image' => array(
'label' => 'LLL:EXT:fefiles/Resources/Private/Language/locallang_db.xlf:image',
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
'image', array(
'appearance' => array(
'createNewRelationLinkTitle' => 'LLL:EXT:cms/locallang_ttc.xlf:images.addFileReference'
),
'minitems' => 0,
'maxitems' => 1,
'foreign_match_fields' => array(
'fieldname' => 'image',
'tablenames' => 'tx_fechat_domain_model_smile',
'table_local' => 'sys_file_reference',
),
), $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
),
),
Can I set upload folder exactly for files for this field ? TYPO3 version 7.6.18
Its not possible through Tca, but you can utilized hook.
in localconf.php file
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['getDefaultUploadFolder']['my_ext'] = 'Vendor\\MYEXT\\Hooks\\BackendUserAuthentication->getDefaultUploadFolder';
in my_ext/Classes/Hooks/BackendUserAuthentication.php
namespace Vendor\MYEXT\Hooks;
class BackendUserAuthentication {
public function getDefaultUploadFolder(Array $params, \TYPO3\CMS\Core\Authentication\BackendUserAuthentication $backendUserAuthentication) {
//Define table name an field for which you want to change upload path
if($params['table'] == 'tx_myext_domain_model_objectdetail' && ($params['field'] == 'mediafiles'||$params['field'] == 'image'))
{
$uploadFolder = new \TYPO3\CMS\Core\Resource\Folder($params['uploadFolder']->getStorage(),'/uploadfolder/','uploadfolder');
return $uploadFolder;
}
return $params['uploadFolder'];
}
}
I created a select in Typo3 TCA, it's looks like this:
'company_address' => array(
'exclude' => 1,
'label' => 'Company Address',
'config' => array(
'type' => 'select',
'foreign_table' => 'pages',
'foreign_table_where' => ' AND doktype = 75',
'items' => array(
array('', 0)
),
'maxitems' => 1
)
),
By default value = uid of record, how to change this ?
I need that value = my_column. Is it possible ?
You can use a itemProcFunc to build your select options like you need them to be. In your TCA you change the config:
'company_address' => array(
'config' => array(
'type' => 'select',
'itemsProcFunc' => 'Vendor\\MyExt\\UserFunc\\TcaProcFunc->companyAddressItems'
'maxitems' => 1
)
)
You can implement your custom function then. I'll give you an example
namespace Vendor\MyExt\UserFunc;
class TcaProcFunc
{
/**
* #param array $config
* #return array
*/
public function companyAddressItems($config)
{
$itemList = [];
$rows = $this->getMySpecialDokTypeRowsFromDb();
foreach ($rows as $row) {
$itemList[] = ['Label of the item', $row['my_column']];
}
$config['items'] = $itemList;
return $config;
}
}
Whatever you store in $config['items'] will be the item List in your select box. To make this (untested) example work you have of course implement the method getMySpecialDokTypeRowsFromDb().
how I can make editing row using ajax with zfdatagrid, thanks
ZF 1.11 -
My Bootstrap
protected function _initZfdatagrid()
{
$this->_config = new Zend_Config_Ini(APPLICATION_PATH .'/configs/grid.ini', 'production');
Zend_Registry::set('config', $this->_config);
if ( #isset(Zend_Registry::get('config')->site->jqGridUrl) ) {
Bvb_Grid_Deploy_JqGrid::$defaultJqGridLibPath = Zend_Registry::get('config')->site->jqGridUrl;
}
}
My Controller
public function indexAction()
{
$grid1 = new Bvb_Grid_Deploy_JqGrid(Zend_Registry::get('config'));
$this->configG1($grid1);
$grid1->setDeployOptions(array
('title'=>'Grado 10A',
'subtitle'=>'School2.0 : Matematicas:'.date('Y-m-d'),
'logo'=>$this->view->baseUrl.'/zfdatagrid/public/images/logotipo.jpg',
));
$this->view->grid = $grid1->deploy();
$this->render('index');
}
public function configG1 ($grid)
{
$select = $this->_db->select()->from('Articulos', array('id', 'titulo', 'fecha','nota', 'publicar', 'dependencia'));
$grid->setSource(new Bvb_Grid_Source_Zend_Select($select));
$grid->updateColumn('id',
array('title' => '#ID', 'hide' => true));
$grid->updateColumn('_action',
array('search' => false, // this will disable search on this field
'order' => 1, 'title' => 'Action', 'width' => 100, 'class' => 'bvb_action bvb_first', 'callback' =>
array('function' => array($this, 'g1ActionBar'), 'params' =>
array('{{ID}}')), 'jqg' =>
array('fixed' => true, 'search' => false)));
$grid->updateColumn('titulo', array('title' => 'Titulo Articulo', 'width' => 260));
$grid->updateColumn('fecha', array('title' => 'Fecha', 'searchType' => "="));
$grid->updateColumn('Nota', array('title' => 'Calificacion (ucase)', 'callback' => array('function' => create_function('$text', 'return strtoupper($text);'), 'params' => array('{{District}}'))));
$grid->setDefaultFilters(array('titulo' => '1'));
$grid->setExport(array(// define parameters for csv export, see Bvb_Grid::getExports
'csv' => array('caption' => 'Csv'),
'pdf' => array('caption' => 'Pdf')));
$grid->setJqgParams(array('caption' => 'jqGrid Example', 'forceFit' => true, 'viewrecords' => false, // show/hide record count right bottom in navigation bar
'rowList' => array(10, 20, 30, 40, 50), // show row number per page control in navigation bar
'altRows' => true)// rows will alternate color
);
$grid->setJqgParam('viewrecords', true);
$grid->jqgViewrecords = true;
$grid->setBvbParams(array('id' => 'ID'));
$grid->setBvbParam('id', 'ID');
$grid->bvbId = 'ID';
$grid->bvbOnInit = 'console.log("this message will not be logged because of call to bvbClearOnInit().");';
$grid->bvbClearOnInit();
$grid->bvbSetOnInit('console.log("jqGrid initiated ! If data are remote they are not loaded at this point.");');
$grid->setAjax(get_class($grid));
}
If you haven't gotten anywhere on this, you might want to look at the jqgrid wiki. They provide information on adding inline cell editing:
http://www.trirand.com/jqgridwiki/doku.php?id=wiki:cell_editing
as well as popup form editing:
http://www.trirand.com/jqgridwiki/doku.php?id=wiki:form_editing
According to the inline cell editing page, adding the cellEdit parameter should enable cell editing. You can provide the url the data is submit to with the cellurl parameter.