SilverStripe DropdownField populated by js - [value] is not a valid option - silverstripe

I've got a SilverStripe form which includes a dropdown field displayed on the front-end of my website.
$fields = new FieldList(
...
DropdownField::create(
'Employer',
'Employer'
)
...
);
....
$actions = new FieldList(
FormAction::create('doReportIssue')->setTitle('Report')
);
$required = new RequiredFields('FirstName', 'LastName');
$form = new Form($this, 'ReportIssueForm', $fields, $actions, $required);
return $form;
I've got some javascript which sets the options in the dropdown.
let employerEl = $("#Form_ReportIssueForm_Employer");
let employers = [{ "name":"employerA" }, { "name":"employerB" }];
employers.forEach((employer) => {
employerEl.append($("<option></option>").val(employer.name).text(employer.name));
});
});
The field is generated correctly in the form, and the javascript correctly populates the options.
However, when I submit the form I get the message
Please select a value within the list provided.
employerA is not a valid option
I don't need this field to be validated server-side.
How do I stop this behaviour from happening?

I worked out a solution, but I'm sure there's a more elegant SilverStripe way of doing it.
I extended the DropdownField class, and made validate always return true.
class NoValidationDropdownField extends DropdownField {
public function validate($validator)
{
return true;
}
}

Related

Change field value and submit node with a custom button

I am attempting to write a module that adds a button to a node type that, when pressed, will change a value of a field in that node and submit the changes. Everything seems to be working, as the button appears correctly and the node submits when it's pressed, but the value of the field remains unchanged. I feel like I'm missing something obvious.
<?php
function iu_buttons_node_view($node, $view_mode, $langcode) {
if ($node->type == 'billing_entry') {
if ($node->field_status['und'][0]['value'] == 'open') {
$form = drupal_get_form('submit_button_form');
$node->content['submit_button'] = $form;
}
}
}
function submit_button_form($form, &$form_submit) {
$form['submit'] = array(
'#type' => 'button',
'#value' => ('Submit'),
'#submit' => array('submit_button_form_submit'),
);
return $form;
}
function submit_button_form_submit($form, &$form_state) {
$node->field_status['und'][0]['value']['#value'] = 'submitted';
}
It's probably worth noting that the field I'm trying to change is a select list. Should I be using a different function than hook_form_submit?
I am assuming you are writing this code in a custom module named iu_buttons and you want to display this button in the node page, not in the node edit form.
In this case, the problem is that you never saved the node in your submit function. Here is a version of your submit function that will save the node.
function submit_button_form_submit($form, &$form_state) {
$node = menu_get_object(); //get the current node
$node->field_status['und'][0]['value']['#value'] = 'submitted';
node_save($node); // save the changed node
}
I think you may be interested in saving only the field, without the need to save the whole node. In this case, you might use the following:
function submit_button_form_submit($form, &$form_state){
$node = new stdClass(); // Create empty object
$node->nid = intval(args(1)); // Include the nid so that Drupal saves the new value to the correct node
$node->field_status['und'][0]['value']['#value'] = 'submitted';
field_attach_update('node', $node); // Save the field
}

Add custom icon to orders' list view in Prestashop

I would like to add new button to order's list view, but I have no idea how to do it:
I want to do it in way that new upgrade will not delete it.
Edit: This new button will just open new browser window so it's completely independent of PrestaShop functionalities. But I would like to put it in this toolbar line.
Thank you for your help!
You could do it with overrides. Create a file called AdminOrdersController.php in your overrides/controllers/admin/ folder, and add the following:
<?php
class AdminOrdersController extends AdminOrdersControllerCore
{
public function initPageHeaderToolbar()
{
parent::initPageHeaderToolbar(); // this will assign native icons
// This is where you add you custom icon
$this->page_header_toolbar_btn['my_custom_icon'] = array(
'href' => self::$currentIndex.'&mycustomaction&token='.$this->token,
'desc' => $this->l('My custom action', null, null, false),
'icon' => 'process-icon-save'
);
}
public function initProcess()
{
parent::initProcess();
if (Tools::getIsset('mycustomaction')) {
if ($this->tabAccess['view'] === '1') {
$this->display = 'mycustomaction';
$this->action = 'mycustomaction';
}
else
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
}
}
public function initContent()
{
parent::initContent();
if ($this->display == 'mycustomaction')
$this->content.= $this->renderMyCustomAction();
}
public function renderMyCustomAction()
{
// this is where you render your custom page.
}
}
Note that this is a quick mock up. It should work, though :)
UPDATE
If you just want the icon to open a new page, leave only the initPageHeaderToolbar method and provide the right href attribute, you can delete the initProcess, initContent and renderMyCustomAction methods. I'll leave them in my original reply in case someone else finds it useful.

Ajax Template Silverstripe Widget

I have added a widget to a Page with a class of Page. The widget php code returns a PaginatedList and it is successfully rendering in my Page.ss template using the $SidebarView tag.
How can I hijack the pagination click to have the widget rendered with a new template? I assume that testing for is_ajax on the index method and doing a $this->renderWith('myTemplate') is not going to work since I only want to render the widget with the new template, not the whole page.
Here is my current Page.php code drawing from Zauberfisch's original answer:
public function index( SS_HTTPRequest $request ) {
$page = $this->data();
if ( $request->isAjax() ) {
$widgetArea = $page->Sidebar();
$widget = $widgetArea->Widgets()->filter( 'ClassName', 'ScbWidget' );
return $widget->renderWith( 'ScbTemplate' );
} else {
return array();
}
}
and here is my widget php code that returns the paginated list to my template:
public function ScbList() {
$list = new PaginatedList( CatalogItem::get()->filter( array( 'SchoolChoirRelease' => 1 ) ), Controller::curr()->getRequest() );
$list->setPageLength( $this->ShowPerPage );
return $list;
}
When the paginated list is returned to the template without ajax, everything works as expected - ?start=2 returns the list offset by 2 items. When I hijack the link and render the widget using the new template, my list is not being rendered in the new template. Here is my js:
ajaxify = function( href, callback ) {
$.ajax( {
url: href,
success: function( data ) {
callback( data );
}
});
};
hijackSubmit = function() {
jqueryMap.$pagination.on( 'click', 'a', function( e ) {
e.preventDefault();
var href = $( this ).attr( 'href' );
ajaxify( href, function( data ) {
jqueryMap.$container.html( data );
} );
});
};
In SilverStripe any object of type ViewableData can be rendered. Page is a subclass of ViewableData, but so is Widget. A lot of objects in SilverStripe extend ViewableData.
This means you are already on the right track.
I am assuming you have 2 variables:
$request a request object of type SS_HTTPRequest
(if you are in a Controller, you can get it like this: $request = $this->getRequest())
$page a page object of type Page or subclass.
(if you are in a Controller, you can get it like this: $page = $this->data())
now you should be able to do:
if ($request->isAjax()) {
$widgetArea = $page->SideBar();
$widget = $widgetArea->Widgets()->filter('ClassName', 'MyWidget')->First();
return $widget->renderWith('MyWidgetTemplate');
}
// do something else
NOTE: if $request->isAjax() is never true, add ?ajax=1 to the URL when you call it in javascript. ?ajax=1 will let SilverStripe know that this is an ajax request.

Drupal Admin form AJAX callback not working

I am trying to implement an AJAX callback to change a drop down list options based on the values of another drop down.I have looked into the examples online and the examples in the examples module. I am trying to implement the example on one of the admin pages forms.
To simplify, I tried to achieve the following: Just to change the title of the second dropdown with a random number once the first dropdown has changed. Please note that I am using a field collection field.
function myaction_form_alter(&$form, &$form_state, $form_id) {
$form['field_programme_permission']['und']['0']['field_programme']['und']['#ajax']=array(
'event' => 'change',
'callback' => 'programmes_ajax_callback',
'method' => 'replace',
'wrapper' => 'countries_wrapper'
);
$form['field_programme_permission']['und']['0']['field_countries']['und']['#title']=rand(1,100);
return $form;
}
function programmes_ajax_callback($form, $form_state) {
return $form['field_programme_permission']['und']['0']['field_countries'];
}
It is as if programmes_ajax_callback is not triggered at all. I see this Drupal AJAX please wait message but nothing actually happens. The weird thing, If I submit the form and it doesn't pass validation, I don't even see this Drupal AJAX "please wait" message. I have simplified the code as much as possible to try to pin point the problem, but it didn't work...
Any ideas?
The problem was caused by the fact that countries_wrapper didn't actually exist as I was actually calling it countries-wrapper somewhere else.
Find below the code that I have actually used. This code covers a muti-value (up to 10) field collection at which one field (countries) in the field collection is dependent on the other (programme). Hopefully, it will prove to be useful for someone.
function mymodule_form_alter(&$form, &$form_state, $form_id) {
for($i=0;$i<10;$i++) {
if(($form_id=='user_register_form') || ($form_id=='user_profile_form')) {
if(isset($form_state['values']['field_programme_permission'][LANGUAGE_NONE][$i]['field_programme'][LANGUAGE_NONE][0]['tid'])) {
$programme_selected= $form_state['values']['field_programme_permission'][LANGUAGE_NONE][$i]['field_programme'][LANGUAGE_NONE][0]['tid'];
} else {
$programme_selected=0;
}
if(isset($form_state['field']['field_programme_permission']['und']['entity'][$i]->field_programme['und'][0]['tid'])){
$programme_selected=$form_state['field']['field_programme_permission']['und']['entity'][$i]->field_programme['und'][0]['tid'];
}
$form['field_programme_permission'][LANGUAGE_NONE][$i]['field_programme'][LANGUAGE_NONE]['#ajax']=array(
'event' => 'change',
'callback' => '_programmes_ajax_callback',
'method' => 'replace',
'wrapper' => 'countries_wrapper'.$i
);
$form['field_programme_permission'][LANGUAGE_NONE][$i]['field_countries'][LANGUAGE_NONE]['#title']='Countries';
$form['field_programme_permission'][LANGUAGE_NONE][$i]['field_countries'][LANGUAGE_NONE]['#prefix']='<div id="countries_wrapper'.$i.'">';
$form['field_programme_permission'][LANGUAGE_NONE][$i]['field_countries'][LANGUAGE_NONE]['#suffix']='</div>';
$form['field_programme_permission'][LANGUAGE_NONE][$i]['field_countries'][LANGUAGE_NONE]['#options']=_countries_ajax_callback($programme_selected);
}
}
return $form;
}
function _programmes_ajax_callback($form, $form_state) {
//we first need to know the triggering element, to know the index of the countries field that we need to affect.
$index= $form_state['triggering_element']['#field_parents'][2];
return $form['field_programme_permission'][LANGUAGE_NONE][$index]['field_countries'];
}
function _countries_ajax_callback($selected) {
$programme_value = $selected;
$options=array();
if(taxonomy_term_load($programme_value)){
$programme_taxonomy=taxonomy_term_load($programme_value);
if(isset($programme_taxonomy->field_countries[LANGUAGE_NONE])) {
$countries=$programme_taxonomy->field_countries[LANGUAGE_NONE];
foreach($countries as $country) {
$country_tid = $country['tid'];
$country_term = taxonomy_term_load($country_tid);
$country_name = $country_term->name;
$options[$country_tid]=$country_name;
}
}
}
return $options;
}

Drupal 6 Form Api adding an item to an existing form

I want to add a new item into an existing form. I have the ID of the form and I know I need to use hook form_alter but not sure how to add it.
function modulename_form_alter(&$form, $form_state, $form_id) {
switch ($form_id) {
case 'form id goes here':
// Need to do something here....
break;
}
}
Because the &$form variable is a reference, whatever you do to it changes the original value. so just add it to $form;
//After, need to do something here:
$form['my_new_field'] = array(
'#type' => 'select',
//etc..
);
//You can also add a new validation here:
$form['#validate'][] = 'my_valiation_callback';
See the drupal api ref for better details:

Resources