I have this code for handling status changes in my model.
<Form.Item
name="status"
label="Status"
>
<Select>
{
statusOptions
?
Object.keys(statusOptions).map(statusId => {
return <Select.Option key={ statusId } value={ statusId }>{ statusKey2Value(statusId) }</Select.Option>;
})
:
null
}
</Select>
</Form.Item>
statusOptions is a JSON object as follows:
{
0: Deleted
1: Active
}
I am using Antd v4.5.1 which recommends handling initialValues directly within the Form component. I basically retrieve the data from the backend and provide the data to the Form component. However, when I try to set selected option for the dropdown, it is being displayed as "1" instead of "Active". I have found a solution provided by Antd Select API which is to hold status value as an object with a label value inside but I didn't really find it optimal to change my backend structure. Can anyone help me with this by any chance?
Try using an optionLabelProp="label" on Select component and place a label={statusOptions[statusId]} on Select.Option. Oh and make Select.Option self-closing.
Related
Newbie hacking my way through. I'm trying to pull rows from an array and display them in a screen. I have the array populated and the snippet of code below works:
return (
buildings.map((building) => {
return <div className="col-md-9">
{building.name}
But when I try to use a component in the statement I get an error. This doesn't work:
return (
buildings.map((building) => {
return <div className="col-md-9">
<Building building={building.name}/>
The Building component is here:
import React from 'react'
function Building({building}) {
return (
<div className="row">
<h1>{building.name}</h1>
</div>
)
}
export default Building
The error I get is here:
src/screens/Homescreen.js Line 34:15: 'Building' is not defined
react/jsx-no-undef
I can provide more details if necessary. I think I'm missing something obvious but I'm stuck at the moment so any help is appreciated.
First check to see if you are importing Building component.
secondly, <Building building={building.name}/> you are passing down the name attribute of building and then in the Building component, trying to access that name attribute. This should be changed to <Building building={building}/>. Fix these to see if the problem continues to exist.
I'm learning Shopware and I got to something I can't figure out how to solve.
I'm writing a test plugin that adds an attribute to the customer. I've added the correspondent field to the Registration form and it saves its value to the db automatically, like I read somewhere in the docs.
Now I wanted to let the attribute be editable in the account profile page, after the password field. I managed to put the input there, and even show the value from the db. But when I change the value and save, the value its not updated. I don't know if it is just a matter of getting the field name right, or do I need to override something else. Or is it just not possible? Any help on how to achieve this would be greatly appreciated.
Relevant code below:
plugin bootstrap
public function install(InstallContext $context)
{
$service = $this->container->get('shopware_attribute.crud_service');
$service->update('s_user_attributes', 'test_field', 'string');
$metaDataCache = Shopware()->Models()->getConfiguration()->getMetadataCacheImpl();
$metaDataCache->deleteAll();
Shopware()->Models()->generateAttributeModels(['s_user_attributes']);
return true;
}
register/personal_fieldset.tpl
{extends file="parent:frontend/register/personal_fieldset.tpl"}
{block name='frontend_register_personal_fieldset_password_description'}
{$smarty.block.parent}
<div class="register--test-field">
<input autocomplete="section-personal test-field"
name="register[personal][attribute][testField]"
type="text"
placeholder="Test Field"
id="testfield"
value="{$form_data.attribute.testField|escape}"
class="register--field{if $errorFlags.testField} has--error{/if}"
/>
</div>
{/block}
account/profile.tpl
{extends file="parent:frontend/account/profile.tpl"}
{block name='frontend_account_profile_profile_required_info'}
<div class="profile--test-field">
<input autocomplete="section-personal test-field"
name="profile[attribute][testfield]"
type="text"
placeholder="Test Field"
id="testfield"
value="{$sUserData.additional.user.test_field|escape}"
class="profile--field{if $errorFlags.testField} has--error{/if}"
/>
</div>
{$smarty.block.parent}
{/block}
The form type that it's used on registration isn't the same you have on profile.
If you check \Shopware\Bundle\AccountBundle\Form\Account\PersonalFormType::buildForm, you can see
$builder->add('attribute', AttributeFormType::class, [
'data_class' => CustomerAttribute::class
]);
That means the attributes are included on form and they will be persisted. That's why you can save the value on registration form.
On profile you have \Shopware\Bundle\AccountBundle\Form\Account\ProfileUpdateFormType. And here the attribute isn't added to form builder.
How to extend the ProfileUpdateFormType?
Subscribe Shopware_Form_Builder on Bootstrap (or on a specific Subscriber class)
$this->subscribeEvent('Shopware_Form_Builder', 'onFormBuild');
Create the method onFormBuild to add your logic
public function onFormBuild(\Enlight_Event_EventArgs $event) {
if ($event->getReference() !== \Shopware\Bundle\AccountBundle\Form\Account\ProfileUpdateFormType::class) {
return;
}
$builder = $event->getBuilder();
$builder->add('attribute', AttributeFormType::class, [
'data_class' => CustomerAttribute::class
]);
}
With this approach all attributes are available on your profile form.
Other possibility you have is using the 'additional' property instead of 'attribute' and then subscribe a controller event or hook a controller action to handle your custom data.
I am playing with node.js and jade and currently have this simple template:
extends layout
block content
h1 #{title}
br
form(action="/updateingredient", method="post")
table.table.table-striped.table-bordered
tr
td Name
td Category
td Available
if (typeof ingredients === "undefined")
tr
td
else
each ingredient in ingredients
tr
td #{ingredient.name}
td #{ingredient.category}
td
input(type="checkbox", name="#{ingredient.id}",
value="#{ingredient.available}", checked=ingredient.available)
button.btn(type="submit") Update Ingredients
When submitting this I get hit in upgradeIngredients as expected:
updateIngredient: function (req, res) {
console.log(req.body);
}
My problem lies in. That the Post only includes the checkboxes that are checked, also the value of checked boxes always seem to be false. I presume that is because that was the value before the form Post.
What I preferably would like is to get all checkbox values in the form, checked or not. Is this possible?
The current output from the updateIngredient method gives me the following when a checkbox is checked (currently just testing with one item):
{ 'b56a5f79-b074-4815-e7e0-4b746b2f65d8': 'false' }
and when unchecked:
{}
Edit
Looking at the constructed HTML I see this for an item:
<tr>
<td>Ost</td>
<td>Mælkeprodukt</td>
<td>
<input
type="checkbox"
name="b56a5f79-b074-4815-e7e0-4b746b2f65d8"
value="false"
checked="false">
</td>
</tr>
Verify that the checkbox HTML is correctly constructed
look in console for errors and warnings
ensure that the boxes all have either "true" or "false" for the checked value.
This example contains working syntax:
Node Express Jade - Checkbox boolean value
After searching some more here on SO, I found this answer: Post the checkboxes that are unchecked
It seems like checkboxes, which are not checked are not part of a form when posting HTML. This is exactly what I am seeing.
I did change my checked code to the following before going down another path.
checked=ingredient.available?"checked":undefined
This did not change anything, and did not give me any data in my form post when unchecked.
So I used the JavaScript approach, adding a submit event handler to my form. I added a new checkbox.js file in my javascripts folder, this code is taken from this answer:
// Add an event listener on #form's submit action...
$("#updateform").submit(
function() {
// For each unchecked checkbox on the form...
$(this).find($("input:checkbox:not(:checked)")).each(
// Create a hidden field with the same name as the checkbox and a value of 0
// You could just as easily use "off", "false", or whatever you want to get
// when the checkbox is empty.
function() {
console.log("hello");
var input = $('<input />');
input.attr('type', 'hidden');
input.attr('name', $(this).attr("name")); // Same name as the checkbox
// append it to the form the checkbox is in just as it's being submitted
var form = $(this)[0].form;
$(form).append(input);
} // end function inside each()
); // end each() argument list
return true; // Don't abort the form submit
} // end function inside submit()
); // end submit() argument list
Then I added the script to the end of my layout.jade file:
script(src='/javascripts/checkbox.js')
And I modified my form to include an ID:
form#updateform(action="/updateingredient", method="post")
And removed the value from the checkbox:
input(type="checkbox", name="#{ingredient.id}",
checked=ingredient.available?"checked":undefined)
Now I get the following when value is unchecked:
{ 'b2a4b035-8371-e620-4626-5eb8959a36b0': '' }
And when checked:
{ 'b2a4b035-8371-e620-4626-5eb8959a36b0': 'on' }
Now in my method I can find out whether it was checked or not with:
var available = req.body[ingredient] === "on" ? true : false;
Where ingredient is the key.
I have a submit button, with the following HTML:
<button type="submit" class="back-button" data-direction="back">Back</button>
The controller method is defined like this:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index(SearchModel searchModel, string SearchBy, string dataDirection)
{
// Code removed for simplicity...
}
When I click the button, my Model is populated, but the dataDirection property is not populated.
What is the correct way to access those data attributes?
This is not a ASP .NET MVC issue.For submit buttons, browsers only send the value of the "value" attribute when the form is submitted. The button's name is used as the parameter name and the value is used as the parameter value.
If you want to send additional parameters with the form based on which button is clicked, you have to use Javascript to listen for the 'click' event of the button and add your custom parameters to the post data or set some hidden field values before submission.
Easiest way is to put a hidden field in your form with name "Direction", listen button click set its value to 'back' or 'next'. And if you have a default value for the direction or you want the last direction value to be set to the hidden field after a postback, you may put a "Direction" property on your model.
Below code shows how you do it with jQuery:
<input type="hidden" name="Direction" value="#Model.Direction" id="fldDirection" />
<script type="text/javascript">
$("[type='submit']").on('click', function() {
if ($(this).data('direction')) {
$("#fldDirection").val($(this).data('direction'));
}
}
</script>
I am using a customised version of search-theme-form.tpl
When I use the search box, I do get transferred to the search page. But the search does not actually take place. The search box on the search results page does work though. This is my search-them-form.tpl.php file (demo :
<input type="text" name="search_theme_form_keys" id="edit-search-theme-form-keys" value="Search" title="Enter the terms you wish to search for" class="logininput" height="24px" onblur="restoreSearch(this)" onfocus="clearInput(this)" />
<input type="submit" name="op" id="edit-submit" value="" class="form-submit" style="display: none;" />
<input type="hidden" name="form_token" id="edit-search-theme-form-form-token" value="<?php print drupal_get_token('search_theme_form'); ?>" />
<input type="hidden" name="form_id" id="edit-search-theme-form" value="search_theme_form" />
There is also a javascript file involved. I guess it's use is pretty clear from the code:
function trim(str) {
return str.replace(/^\s+|\s+$/g, '');
}
function clearInput(e) {
e.value=""; // clear default text when clicked
e.className="longininput_onfocus"; //change class
}
function restoreSearch(e) {
if (trim(e.value) == '') {
{
e.value="Search"; // reset default text onBlur
e.className="logininput"; //reset class
}
}
}
What can be the problem and how can I fix it?
Apparently, you cannot directly modify the HTML in search-theme-form.tpl.php since thats not the right way to do it. So my adding the class and onFocus and onBlur attributes was the problem.
The correct way to do it is to modify the themes template.php file. Basically we will be using form_alter() to modify the form elements. Since using the HTML way is wrong. Take a look at the code below (taken from : here )
<?php
/**
* Override or insert PHPTemplate variables into the search_theme_form template.
*
* #param $vars
* A sequential array of variables to pass to the theme template.
* #param $hook
* The name of the theme function being called (not used in this case.)
*/
function yourthemename_preprocess_search_theme_form(&$vars, $hook) {
// Note that in order to theme a search block you should rename this function
// to yourthemename_preprocess_search_block_form and use
// 'search_block_form' instead of 'search_theme_form' in the customizations
// bellow.
// Modify elements of the search form
$vars['form']['search_theme_form']['#title'] = t('');
// Set a default value for the search box
$vars['form']['search_theme_form']['#value'] = t('Search this Site');
// Add a custom class and placeholder text to the search box
$vars['form']['search_theme_form']['#attributes'] = array('class' => 'NormalTextBox txtSearch',
'onfocus' => "if (this.value == 'Search this Site') {this.value = '';}",
'onblur' => "if (this.value == '') {this.value = 'Search this Site';}");
// Change the text on the submit button
//$vars['form']['submit']['#value'] = t('Go');
// Rebuild the rendered version (search form only, rest remains unchanged)
unset($vars['form']['search_theme_form']['#printed']);
$vars['search']['search_theme_form'] = drupal_render($vars['form']['search_theme_form']);
$vars['form']['submit']['#type'] = 'image_button';
$vars['form']['submit']['#src'] = path_to_theme() . '/images/search.jpg';
// Rebuild the rendered version (submit button, rest remains unchanged)
unset($vars['form']['submit']['#printed']);
$vars['search']['submit'] = drupal_render($vars['form']['submit']);
// Collect all form elements to make it easier to print the whole form.
$vars['search_form'] = implode($vars['search']);
}
?>
In yourthemename_preprocess_search_theme_form - 'yourthemename' will obviously reflect the name of your custom theme. Basically the code is self-explanatory. what with the comments and all.
So, basically thats the way it works.