Gadgetto Posted December 30, 2019 Share Posted December 30, 2019 In a ProcessModule I'm trying to set an API InputFieldSelect or InputFieldText to readyonly using the HTML attr readonly="readonly". I have tried this but this has no effect: /** @var InputfieldSelect $f */ $f = $modules->get('InputfieldSelect'); if ($action == 'edit') $f->attr('readonly', 'readonly'); $f->name = 'type'; $f->label = $this->_('Type'); $f->required = true; $f->value = $type; $f->columnWidth = 100; $f->addOptions($this->getDiscountsTypes()); The HTML source looks OK (it has the readonly attr), but the readonly attribute seems to be ignored. <select id="Inputfield_type" class="required uk-select" name="type" readonly="readonly"> ... </select> Is this possible? Link to comment Share on other sites More sharing options...
kongondo Posted December 30, 2019 Share Posted December 30, 2019 1 hour ago, Gadgetto said: <select id="Inputfield_type" class="required uk-select" name="type" readonly="readonly"> ... </select> HTML specs say select tag does not have readonly attribute. Use disabled instead. I think a disabled select will not POST though. 1 Link to comment Share on other sites More sharing options...
flydev Posted December 30, 2019 Share Posted December 30, 2019 (edited) 13 minutes ago, kongondo said: I think a disabled select will not POST though. Correct, the trick here is to disable all options except the one which need to be submited. <select> <option value="1" disabled>one</option> <option value="2" disabled>two</option> <option value="3" selected>three</option> </select> Edited December 30, 2019 by flydev example 1 Link to comment Share on other sites More sharing options...
Gadgetto Posted December 30, 2019 Author Share Posted December 30, 2019 @kongondo, @flydev, aah, I'm so stupid - forgot that <select> doesn't have attr readonly... I'll solve this by setting the <select> disabled and adding a hidden field with the preselected value instead. Link to comment Share on other sites More sharing options...
bernhard Posted January 2, 2020 Share Posted January 2, 2020 Can't you just set the inputfield collapsed to collapsedNoLocked ? https://processwire.com/api/ref/inputfield/#pwapi-methods-collapsed-constants Link to comment Share on other sites More sharing options...
Gadgetto Posted January 2, 2020 Author Share Posted January 2, 2020 35 minutes ago, bernhard said: Can't you just set the inputfield collapsed to collapsedNoLocked ? https://processwire.com/api/ref/inputfield/#pwapi-methods-collapsed-constants Setting to Inputfield::collapsedNoLocked renders the field as simple list item without a form field element. So the locked/readonly value won't be submitted. Link to comment Share on other sites More sharing options...
Gadgetto Posted January 2, 2020 Author Share Posted January 2, 2020 The best way to simulate a readonly InputfieldSelect seems to be: set an disabled attr to the desired select field "myfield" change the name of the select field to e.g. "myfield_disabled" use an additional hidden form field and give it the name of the disabled select field "myfield" The only problem I have after this is, that the form processing complains that the field has no value - but this should be solvable... Link to comment Share on other sites More sharing options...
bernhard Posted January 2, 2020 Share Posted January 2, 2020 I think I don't understand what you are trying to do. Why do you need a readonly select? What is the difference to a locked field that just shows the value? Link to comment Share on other sites More sharing options...
Gadgetto Posted January 2, 2020 Author Share Posted January 2, 2020 4 minutes ago, bernhard said: I think I don't understand what you are trying to do. Why do you need a readonly select? What is the difference to a locked field that just shows the value? The locked/disabled field value won't be in the post array. The value should be posted but not be editable. I feed the SnipCart REST API with an array of key->value pairs and the "not editable" value still needs to be in the array. Link to comment Share on other sites More sharing options...
bernhard Posted January 2, 2020 Share Posted January 2, 2020 OK thx for the clarification ? Link to comment Share on other sites More sharing options...
Gadgetto Posted January 2, 2020 Author Share Posted January 2, 2020 4 minutes ago, bernhard said: OK thx for the clarification ? The problem is $form->processInput($input->post) won't populate the disabled field as the value isn't in the post array. And the disabled select field is empty after posting. So I'm now trying to get the field populated "after" the form is processed or something else - really don't know how to do it currently ... Link to comment Share on other sites More sharing options...
Gadgetto Posted January 2, 2020 Author Share Posted January 2, 2020 Just see that processInput is hookable. Maybe it's possible to hook into this method and "simulate" the processing for the disabled field? Link to comment Share on other sites More sharing options...
bernhard Posted January 2, 2020 Share Posted January 2, 2020 It would be great to get a more detailed description of your problem and what you have so far and what you want to do and what and why the current solution is a problem. You can of course hook processInput and you can set any values there as you like. But it's hard to give an advice when you don't have the bigger picture ? Link to comment Share on other sites More sharing options...
Gadgetto Posted January 2, 2020 Author Share Posted January 2, 2020 Here is the complete method to process the form! Please note: This code isn't finished and some parts (e.g. validation and sanitation part) may look unnecessary... The form can be used for editing (update) or adding (create) SnipCart discounts. In editing mode the method is called with a SnipCart payload ($item) array from REST API and the form is populated with the fetched values. In adding mode the form is populated with default values. Some fields like the documented field below in code (near the middle of the code), needs to be readonly in edit mode as not all parts of a SnipCart discount can be changed after creation. The problem is, a SELECT field can't be set to "readonly" in HTML - only "disabled" is possible. But a disabled field won't be submitted when form is posted. For a good user experience I'd like to simulate a readonly field and submit the value of the disabled select field with the help of a hidden field. This works so far, except that I wasn't able to populate the disabled select field after the form was submitted and the $form->processInput($input->post) method was called. This is the problem I'd like to solve. Maybe someone has an idea on how to do this. Spoiler /** * Render and process the discount form. * (Edit or Add) * * @param array $item (optional) * @param string $ret A return URL (optional) * @return markup * */ private function _processDiscountForm($item = null, $ret = '') { $modules = $this->wire('modules'); $sanitizer = $this->wire('sanitizer'); $input = $this->wire('input'); $session = $this->wire('session'); $mode = ($item) ? 'edit' : 'add'; $expiresDateFormat = 'Y-m-d'; $expiresPlaceholder = 'YYYY-MM-DD'; $expiresMinDate = wireDate($expiresDateFormat); if (!$input->post->saving_discount_active) { if ($mode == 'edit') { // Get values from payload $discount = array( 'id' => $item['id'], 'name' => $item['name'], 'expires' => $item['expires'], 'maxNumberOfUsages' => $item['maxNumberOfUsages'], 'currency' => (isset($item['currency']) ? $item['currency'] : ''), // currency field isn't always present 'combinable' => $item['combinable'], 'type' => $item['type'], 'type_disabled' => $item['type'], // needed to simulate a readonly select in edit mode 'amount' => $item['amount'], 'rate' => $item['rate'], 'alternatePrice' => $item['alternatePrice'], 'shippingDescription' => $item['shippingDescription'], 'shippingCost' => $item['shippingCost'], 'shippingGuaranteedDaysToDelivery' => $item['shippingGuaranteedDaysToDelivery'], // ... more fields to be added 'trigger' => $item['trigger'], ); } else { // Set default values (if action = add) $discount = array( 'id' => '', 'name' => '', 'expires' => '', 'maxNumberOfUsages' => 1, 'currency' => '', 'combinable' => '1', 'type' => 'FixedAmount', 'amount' => '', 'rate' => '', 'alternatePrice' => '', 'shippingDescription' => '', 'shippingCost' => '', 'shippingGuaranteedDaysToDelivery' => '', // ... more fields to be added 'trigger' => 'Code', ); } } /** @var InputfieldForm $form */ $form = $modules->get('InputfieldForm'); $form->attr('id', 'DiscountForm'); $form->attr('action', $this->currentUrl); $form->attr('method', 'post'); if ($ret) { /** @var InputfieldHidden $f */ $f = $modules->get('InputfieldHidden'); $f->attr('name', 'ret'); $f->attr('value', urlencode($ret)); $form->add($f); } /** @var InputfieldHidden $f */ $f = $modules->get('InputfieldHidden'); $f->attr('name', 'saving_discount_active'); $f->attr('value', true); $form->add($f); /** @var InputfieldHidden $f */ $f = $modules->get('InputfieldHidden'); $f->attr('name', 'id'); $form->add($f); /** @var InputfieldFieldset $fieldset */ $fieldset = $modules->get('InputfieldFieldset'); $fieldset->label = $this->_('General Information'); $fieldset->icon = 'info-circle'; $form->add($fieldset); /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'name'); $f->label = $this->_('Discount name'); $f->required = true; $f->columnWidth = 50; $fieldset->add($f); /** @var InputfieldDatetime $f */ $f = $modules->get('InputfieldDatetime'); $f->attr('name', 'expires'); $f->attr('placeholder', $expiresPlaceholder); $f->label = $this->_('Expires'); $f->detail = $this->_('Leave empty to never expire'); $f->size = 100; $f->datepicker = InputfieldDatetime::datepickerFocus; $f->dateInputFormat = $expiresDateFormat; $f->columnWidth = 50; $fieldset->add($f); /** @var InputfieldInteger $f */ $f = $modules->get('InputfieldInteger'); $f->attr('name', 'maxNumberOfUsages'); $f->label = $this->_('Maximum number of usages'); $f->detail = $this->_('Leave empty to enable unlimited usage'); $f->size = 100; $f->min = 1; $f->columnWidth = 50; $fieldset->add($f); /** @var InputfieldSelect $f */ $f = $modules->get('InputfieldSelect'); $f->attr('name', 'currency'); $f->label = $this->_('Currency'); $f->columnWidth = 50; $supportedCurrencies = CurrencyFormat::getSupportedCurrencies(); foreach ($this->currencies as $currencyOption) { $currencyLabel = isset($supportedCurrencies[$currencyOption]) ? $supportedCurrencies[$currencyOption] : $currencyOption; $f->addOption($currencyOption, $currencyLabel); } $fieldset->add($f); /** @var InputfieldCheckbox $f */ $f = $modules->get('InputfieldCheckbox'); $f->attr('name', 'combinable'); $f->label = $this->_('Combination with other discounts allowed?'); $fieldset->add($f); /** @var InputfieldFieldset $fieldset */ $fieldset = $modules->get('InputfieldFieldset'); $fieldset->label = $this->_('Choose Discount Actions'); $fieldset->icon = 'cogs'; $fieldset->set('themeOffset', 1); $form->add($fieldset); // // // // The following field (+ the next hidden field) is meant to simulate a readonly InputfieldSelect. // // The problem is, the select field needs to be populated with a value even when "disabled" // which doesn't work out of the box, as $form->processInput($input->post) can't populate it // because the disabled field isn't submitted. // // // /** @var InputfieldSelect $f */ $f = $modules->get('InputfieldSelect'); if ($mode == 'edit') { // simulate a readonly select in edit mode $f->attr('name', 'type_disabled'); $f->attr('disabled', 'disabled'); } else { $f->attr('name', 'type'); } $f->addClass('InputfieldMaxWidth'); $f->label = $this->_('Type'); $f->required = true; $f->addOptions($this->getDiscountsTypes()); $fieldset->add($f); if ($mode == 'edit') { // needed to simulate a readonly select in edit mode /** @var InputfieldHidden $f */ $f = $modules->get('InputfieldHidden'); $f->attr('name', 'type'); $fieldset->add($f); } /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'amount'); $f->attr('pattern', '[-+]?[0-9]*[.]?[0-9]+'); $f->label = $this->_('Amount'); $f->detail = $this->_('Decimal with a dot (.) as separator e.g. 19.99'); $f->required = true; $f->showIf = 'type=FixedAmount|FixedAmountOnItems|FixedAmountOnCategory|AmountOnSubscription'; $f->requiredIf = 'type=FixedAmount|FixedAmountOnItems|FixedAmountOnCategory|AmountOnSubscription'; $fieldset->add($f); /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'rate'); $f->attr('pattern', '[-+]?[0-9]*[.]?[0-9]+'); $f->label = $this->_('Rate in %'); $f->detail = $this->_('Decimal with a dot (.) as separator e.g. 2.5'); $f->required = true; $f->showIf = 'type=Rate|RateOnItems|RateOnCategory|RateOnSubscription'; $f->requiredIf = 'type=Rate|RateOnItems|RateOnCategory|RateOnSubscription'; $fieldset->add($f); /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'alternatePrice'); $f->label = $this->_('Alternate price list'); $f->detail = $this->_('The name of the alternate price list to use'); $f->required = true; $f->showIf = 'type=AlternatePrice'; $f->requiredIf = 'type=AlternatePrice'; $fieldset->add($f); /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'shippingDescription'); $f->label = $this->_('Shipping description'); $f->detail = $this->_('The shipping method name that will be displayed to your customers'); $f->required = true; $f->showIf = 'type=Shipping'; $f->requiredIf = 'type=Shipping'; $fieldset->add($f); /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'shippingCost'); $f->attr('pattern', '[-+]?[0-9]*[.]?[0-9]+'); $f->label = $this->_('Shipping amount'); $f->detail = $this->_('Decimal with a dot (.) as separator e.g. 4.5'); $f->required = true; $f->showIf = 'type=Shipping'; $f->requiredIf = 'type=Shipping'; $f->columnWidth = 50; $fieldset->add($f); /** @var InputfieldInteger $f */ $f = $modules->get('InputfieldInteger'); $f->attr('name', 'shippingGuaranteedDaysToDelivery'); $f->label = $this->_('Guaranteed days to delivery'); $f->detail = $this->_('The number of days it will take for shipping (can be empty)'); $f->size = 100; $f->min = 1; $f->showIf = 'type=Shipping'; $f->columnWidth = 50; $fieldset->add($f); // more fields to be added ... /** @var InputfieldFieldset $fieldset */ $fieldset = $modules->get('InputfieldFieldset'); $fieldset->label = $this->_('Choose Discount Conditions'); $fieldset->icon = 'scissors'; $form->add($fieldset); /** @var InputfieldSelect $f */ $f = $modules->get('InputfieldSelect'); $f->attr('name', 'trigger'); $f->addClass('InputfieldMaxWidth'); $f->label = $this->_('Trigger'); $f->required = true; $f->addOptions($this->getDiscountsTriggers()); $fieldset->add($f); // more fields to be added ... /** @var InputfieldSubmit $btn */ $btn = $modules->get('InputfieldSubmit'); $btn->attr('id', 'SaveDiscountButton'); $btn->attr('name', 'save_discount'); $btn->attr('value', $this->_('Save discount')); $form->add($btn); // Render form without processing if not submitted if (!$input->post->saving_discount_active) { $form->populateValues($discount); return $form->render(); } $form->processInput($input->post); // Get values and validate input $name = $form->get('name'); $nameValue = $name->value; $expires = $form->get('expires'); $expiresValue = $expires->value; if ($mode == 'add' && $expiresValue && !$sanitizer->date($expiresValue, $expiresDateFormat, array('min' => $expiresMinDate))) { $expires->error(sprintf($this->_('Minimum allowed date is %s (today)'), $expiresMinDate)); } $maxNumberOfUsages = $form->get('maxNumberOfUsages'); $maxNumberOfUsagesValue = $maxNumberOfUsages->value; $currency = $form->get('currency'); $currencyValue = $currency->value; $combinable = $form->get('combinable'); $combinableValue = $combinable->value; $type = $form->get('type'); $typeValue = $type->value; $amount = $form->get('amount'); $amountValue = $amount->value; if ($amountValue && !checkPattern($amountValue, '^[-+]?[0-9]*[.]?[0-9]+$')) { $amount->error($this->_('Wrong format! Please use decimal with a dot (.) as separator e.g. 19.99')); } $rate = $form->get('rate'); $rateValue = $rate->value; if ($rateValue && !checkPattern($rateValue, '^[-+]?[0-9]*[.]?[0-9]+$')) { $rate->error($this->_('Wrong format! Please use decimal with a dot (.) as separator e.g. 2.5')); } $alternatePrice = $form->get('alternatePrice'); $alternatePriceValue = $alternatePrice->value; $shippingDescription = $form->get('shippingDescription'); $shippingDescriptionValue = $shippingDescription->value; $shippingCost = $form->get('shippingCost'); $shippingCostValue = $shippingCost->value; if ($shippingCostValue && !checkPattern($shippingCostValue, '^[-+]?[0-9]*[.]?[0-9]+$')) { $shippingCost->error($this->_('Wrong format! Please use decimal with a dot (.) as separator e.g. 4.5')); } $shippingGuaranteedDaysToDelivery = $form->get('shippingGuaranteedDaysToDelivery'); $shippingGuaranteedDaysToDeliveryValue = $shippingGuaranteedDaysToDelivery->value; $trigger = $form->get('trigger'); $triggerValue = $trigger->value; if ($form->getErrors()) { // The form is processed and populated but contains errors return $form->render(); } // Sanitize and prepare input for saving $fieldValues = array( 'name' => $nameValue, 'expires' => $sanitizer->date($expiresValue, $expiresDateFormat) . 'T23:00:00Z', 'maxNumberOfUsages' => $sanitizer->int($maxNumberOfUsagesValue), 'currency' => $sanitizer->text($currencyValue), 'combinable' => $combinableValue, 'type' => $sanitizer->text($typeValue), 'amount' => $sanitizer->text($amountValue), // don't santize to float because we always need . as decimal separator 'rate' => $sanitizer->text($rateValue), // don't santize to float because we always need . as decimal separator 'alternatePrice' => $sanitizer->text($alternatePriceValue), 'shippingDescription' => $sanitizer->text($shippingDescriptionValue), 'shippingCost' => $sanitizer->text($shippingCostValue), // don't santize to float because we always need . as decimal separator 'shippingGuaranteedDaysToDelivery' => $sanitizer->text($shippingGuaranteedDaysToDeliveryValue), 'trigger' => $sanitizer->text($triggerValue), ); bd($fieldValues); /* $statusValue = $sanitizer->text($statusValue); $trackingNumberValue = $sanitizer->text($trackingNumberValue); $trackingUrlValue = $sanitizer->httpUrl($trackingUrlValue); $deliveryMethodValue = $sanitizer->option($deliveryMethodValue, array('Email', 'None')); if ($mode == 'edit') { $success = $this->_updateDiscount($id, $fieldValues); } else { $success = $this->_createDiscount($fieldValues); } if ($success) { // Reset cache for this order and redirect to itself to display updated values $this->wire('sniprest')->deleteDiscountCache($id); $redirectUrl = $this->currentUrl . '?modal=1'; if ($ret) $redirectUrl .= '&ret=' . urlencode($ret); $session->redirect($redirectUrl); } */ return $form->render(); } Link to comment Share on other sites More sharing options...
Gadgetto Posted January 2, 2020 Author Share Posted January 2, 2020 Oh damn - I have it! just add this line before processing input: // Manually write values for disabled fields to WireInputData before processing form input $input->post->set('type_disabled', $input->post->type); $form->processInput($input->post); It's that easy! ProcessWire rocks! Link to comment Share on other sites More sharing options...
Gadgetto Posted January 2, 2020 Author Share Posted January 2, 2020 Here is the complete code - now with working simulated "readonly" InputfieldSelect: Spoiler /** * Render and process the discount form. * (Edit or Add) * * @param array $item (optional) * @param string $ret A return URL (optional) * @return markup * */ private function _processDiscountForm($item = null, $ret = '') { $modules = $this->wire('modules'); $sanitizer = $this->wire('sanitizer'); $input = $this->wire('input'); $session = $this->wire('session'); $mode = ($item) ? 'edit' : 'add'; $expiresDateFormat = 'Y-m-d'; $expiresPlaceholder = 'YYYY-MM-DD'; $expiresMinDate = wireDate($expiresDateFormat); if (!$input->post->saving_discount_active) { if ($mode == 'edit') { // Get values from payload $discount = array( 'id' => $item['id'], 'name' => $item['name'], 'expires' => $item['expires'], 'maxNumberOfUsages' => $item['maxNumberOfUsages'], 'currency' => (isset($item['currency']) ? $item['currency'] : ''), // currency field isn't always present 'combinable' => $item['combinable'], 'type' => $item['type'], 'type_disabled' => $item['type'], // needed to simulate a readonly select in edit mode 'amount' => $item['amount'], 'rate' => $item['rate'], 'alternatePrice' => $item['alternatePrice'], 'shippingDescription' => $item['shippingDescription'], 'shippingCost' => $item['shippingCost'], 'shippingGuaranteedDaysToDelivery' => $item['shippingGuaranteedDaysToDelivery'], 'trigger' => $item['trigger'], 'trigger_disabled' => $item['trigger'], // needed to simulate a readonly select in edit mode ); } else { // Set default values (if action = add) $discount = array( 'id' => '', 'name' => '', 'expires' => '', 'maxNumberOfUsages' => 1, 'currency' => '', 'combinable' => '1', 'type' => 'FixedAmount', 'amount' => '', 'rate' => '', 'alternatePrice' => '', 'shippingDescription' => '', 'shippingCost' => '', 'shippingGuaranteedDaysToDelivery' => '', 'trigger' => 'Code', ); } } /** @var InputfieldForm $form */ $form = $modules->get('InputfieldForm'); $form->attr('id', 'DiscountForm'); $form->attr('action', $this->currentUrl); $form->attr('method', 'post'); if ($ret) { /** @var InputfieldHidden $f */ $f = $modules->get('InputfieldHidden'); $f->attr('name', 'ret'); $f->attr('value', urlencode($ret)); $form->add($f); } /** @var InputfieldHidden $f */ $f = $modules->get('InputfieldHidden'); $f->attr('name', 'saving_discount_active'); $f->attr('value', true); $form->add($f); /** @var InputfieldHidden $f */ $f = $modules->get('InputfieldHidden'); $f->attr('name', 'id'); $form->add($f); /** @var InputfieldFieldset $fieldset */ $fieldset = $modules->get('InputfieldFieldset'); $fieldset->label = $this->_('General Information'); $fieldset->icon = 'info-circle'; $form->add($fieldset); /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'name'); $f->label = $this->_('Discount name'); $f->required = true; $f->columnWidth = 50; $fieldset->add($f); /** @var InputfieldDatetime $f */ $f = $modules->get('InputfieldDatetime'); $f->attr('name', 'expires'); $f->attr('placeholder', $expiresPlaceholder); $f->label = $this->_('Expires'); $f->detail = $this->_('Leave empty to never expire'); $f->size = 100; $f->datepicker = InputfieldDatetime::datepickerFocus; $f->dateInputFormat = $expiresDateFormat; $f->columnWidth = 50; $fieldset->add($f); /** @var InputfieldInteger $f */ $f = $modules->get('InputfieldInteger'); $f->attr('name', 'maxNumberOfUsages'); $f->label = $this->_('Maximum number of usages'); $f->detail = $this->_('Leave empty to enable unlimited usage'); $f->size = 100; $f->min = 1; $f->columnWidth = 50; $fieldset->add($f); /** @var InputfieldSelect $f */ $f = $modules->get('InputfieldSelect'); $f->attr('name', 'currency'); $f->label = $this->_('Currency'); $f->columnWidth = 50; $supportedCurrencies = CurrencyFormat::getSupportedCurrencies(); foreach ($this->currencies as $currencyOption) { $currencyLabel = isset($supportedCurrencies[$currencyOption]) ? $supportedCurrencies[$currencyOption] : $currencyOption; $f->addOption($currencyOption, $currencyLabel); } $fieldset->add($f); /** @var InputfieldCheckbox $f */ $f = $modules->get('InputfieldCheckbox'); $f->attr('name', 'combinable'); $f->label = $this->_('Combination with other discounts allowed?'); $fieldset->add($f); /** @var InputfieldFieldset $fieldset */ $fieldset = $modules->get('InputfieldFieldset'); $fieldset->label = $this->_('Choose Discount Actions'); $fieldset->icon = 'cogs'; $fieldset->set('themeOffset', 1); $form->add($fieldset); /** @var InputfieldSelect $f */ $f = $modules->get('InputfieldSelect'); if ($mode == 'edit') { // simulate a readonly select in edit mode $f->attr('name', 'type_disabled'); $f->attr('disabled', 'disabled'); } else { $f->attr('name', 'type'); } $f->addClass('InputfieldMaxWidth'); $f->label = $this->_('Type'); $f->required = true; $f->addOptions($this->getDiscountsTypes()); $fieldset->add($f); if ($mode == 'edit') { // needed to simulate a readonly select in edit mode /** @var InputfieldHidden $f */ $f = $modules->get('InputfieldHidden'); $f->attr('name', 'type'); $fieldset->add($f); } /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'amount'); $f->attr('pattern', '[-+]?[0-9]*[.]?[0-9]+'); $f->label = $this->_('Amount'); $f->detail = $this->_('Decimal with a dot (.) as separator e.g. 19.99'); $f->required = true; $f->showIf = 'type=FixedAmount|FixedAmountOnItems|FixedAmountOnCategory|AmountOnSubscription'; $f->requiredIf = 'type=FixedAmount|FixedAmountOnItems|FixedAmountOnCategory|AmountOnSubscription'; $fieldset->add($f); /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'rate'); $f->attr('pattern', '[-+]?[0-9]*[.]?[0-9]+'); $f->label = $this->_('Rate in %'); $f->detail = $this->_('Decimal with a dot (.) as separator e.g. 2.5'); $f->required = true; $f->showIf = 'type=Rate|RateOnItems|RateOnCategory|RateOnSubscription'; $f->requiredIf = 'type=Rate|RateOnItems|RateOnCategory|RateOnSubscription'; $fieldset->add($f); /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'alternatePrice'); $f->label = $this->_('Alternate price list'); $f->detail = $this->_('The name of the alternate price list to use'); $f->required = true; $f->showIf = 'type=AlternatePrice'; $f->requiredIf = 'type=AlternatePrice'; $fieldset->add($f); /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'shippingDescription'); $f->label = $this->_('Shipping description'); $f->detail = $this->_('The shipping method name that will be displayed to your customers'); $f->required = true; $f->showIf = 'type=Shipping'; $f->requiredIf = 'type=Shipping'; $fieldset->add($f); /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'shippingCost'); $f->attr('pattern', '[-+]?[0-9]*[.]?[0-9]+'); $f->label = $this->_('Shipping amount'); $f->detail = $this->_('Decimal with a dot (.) as separator e.g. 4.5'); $f->required = true; $f->showIf = 'type=Shipping'; $f->requiredIf = 'type=Shipping'; $f->columnWidth = 50; $fieldset->add($f); /** @var InputfieldInteger $f */ $f = $modules->get('InputfieldInteger'); $f->attr('name', 'shippingGuaranteedDaysToDelivery'); $f->label = $this->_('Guaranteed days to delivery'); $f->detail = $this->_('The number of days it will take for shipping (can be empty)'); $f->size = 100; $f->min = 1; $f->showIf = 'type=Shipping'; $f->columnWidth = 50; $fieldset->add($f); /** @var InputfieldFieldset $fieldset */ $fieldset = $modules->get('InputfieldFieldset'); $fieldset->label = $this->_('Choose Discount Conditions'); $fieldset->icon = 'scissors'; $form->add($fieldset); /** @var InputfieldSelect $f */ $f = $modules->get('InputfieldSelect'); if ($mode == 'edit') { // simulate a readonly select in edit mode $f->attr('name', 'trigger_disabled'); $f->attr('disabled', 'disabled'); } else { $f->attr('name', 'trigger'); } $f->addClass('InputfieldMaxWidth'); $f->label = $this->_('Trigger'); $f->required = true; $f->addOptions($this->getDiscountsTriggers()); $fieldset->add($f); if ($mode == 'edit') { // needed to simulate a readonly select in edit mode /** @var InputfieldHidden $f */ $f = $modules->get('InputfieldHidden'); $f->attr('name', 'trigger'); $fieldset->add($f); } /** @var InputfieldSubmit $btn */ $btn = $modules->get('InputfieldSubmit'); $btn->attr('id', 'SaveDiscountButton'); $btn->attr('name', 'save_discount'); $btn->attr('value', $this->_('Save discount')); $form->add($btn); // Render form without processing if not submitted if (!$input->post->saving_discount_active) { $form->populateValues($discount); return $form->render(); } // Manually write values for disabled fields to WireInputData before processing form input $input->post->set('type_disabled', $input->post->type); $input->post->set('trigger_disabled', $input->post->trigger); $form->processInput($input->post); // Get values and validate input $name = $form->get('name'); $nameValue = $name->value; $expires = $form->get('expires'); $expiresValue = $expires->value; if ($mode == 'add' && $expiresValue && !$sanitizer->date($expiresValue, $expiresDateFormat, array('min' => $expiresMinDate))) { $expires->error(sprintf($this->_('Minimum allowed date is %s (today)'), $expiresMinDate)); } $maxNumberOfUsages = $form->get('maxNumberOfUsages'); $maxNumberOfUsagesValue = $maxNumberOfUsages->value; $currency = $form->get('currency'); $currencyValue = $currency->value; $combinable = $form->get('combinable'); $combinableValue = $combinable->value; $type = $form->get('type'); $typeValue = $type->value; $amount = $form->get('amount'); $amountValue = $amount->value; if ($amountValue && !checkPattern($amountValue, '^[-+]?[0-9]*[.]?[0-9]+$')) { $amount->error($this->_('Wrong format! Please use decimal with a dot (.) as separator e.g. 19.99')); } $rate = $form->get('rate'); $rateValue = $rate->value; if ($rateValue && !checkPattern($rateValue, '^[-+]?[0-9]*[.]?[0-9]+$')) { $rate->error($this->_('Wrong format! Please use decimal with a dot (.) as separator e.g. 2.5')); } $alternatePrice = $form->get('alternatePrice'); $alternatePriceValue = $alternatePrice->value; $shippingDescription = $form->get('shippingDescription'); $shippingDescriptionValue = $shippingDescription->value; $shippingCost = $form->get('shippingCost'); $shippingCostValue = $shippingCost->value; if ($shippingCostValue && !checkPattern($shippingCostValue, '^[-+]?[0-9]*[.]?[0-9]+$')) { $shippingCost->error($this->_('Wrong format! Please use decimal with a dot (.) as separator e.g. 4.5')); } $shippingGuaranteedDaysToDelivery = $form->get('shippingGuaranteedDaysToDelivery'); $shippingGuaranteedDaysToDeliveryValue = $shippingGuaranteedDaysToDelivery->value; $trigger = $form->get('trigger'); $triggerValue = $trigger->value; if ($form->getErrors()) { // The form is processed and populated but contains errors return $form->render(); } // Sanitize and prepare input for saving $fieldValues = array( 'name' => $nameValue, 'expires' => $sanitizer->date($expiresValue, $expiresDateFormat) . 'T23:00:00Z', 'maxNumberOfUsages' => $sanitizer->int($maxNumberOfUsagesValue), 'currency' => $sanitizer->text($currencyValue), 'combinable' => $combinableValue, 'type' => $sanitizer->text($typeValue), 'amount' => $sanitizer->text($amountValue), // don't santize to float because we always need . as decimal separator 'rate' => $sanitizer->text($rateValue), // don't santize to float because we always need . as decimal separator 'alternatePrice' => $sanitizer->text($alternatePriceValue), 'shippingDescription' => $sanitizer->text($shippingDescriptionValue), 'shippingCost' => $sanitizer->text($shippingCostValue), // don't santize to float because we always need . as decimal separator 'shippingGuaranteedDaysToDelivery' => $sanitizer->text($shippingGuaranteedDaysToDeliveryValue), 'trigger' => $sanitizer->text($triggerValue), ); bd($fieldValues); /* $statusValue = $sanitizer->text($statusValue); $trackingNumberValue = $sanitizer->text($trackingNumberValue); $trackingUrlValue = $sanitizer->httpUrl($trackingUrlValue); $deliveryMethodValue = $sanitizer->option($deliveryMethodValue, array('Email', 'None')); if ($mode == 'edit') { $success = $this->_updateDiscount($id, $fieldValues); } else { $success = $this->_createDiscount($fieldValues); } if ($success) { // Reset cache for this order and redirect to itself to display updated values $this->wire('sniprest')->deleteDiscountCache($id); $redirectUrl = $this->currentUrl . '?modal=1'; if ($ret) $redirectUrl .= '&ret=' . urlencode($ret); $session->redirect($redirectUrl); } */ return $form->render(); } 1 Link to comment Share on other sites More sharing options...
szabesz Posted January 2, 2020 Share Posted January 2, 2020 3 hours ago, Gadgetto said: Here is the complete code - now with working simulated "readonly" InputfieldSelect: Thanks! However, to make the thread readable, could you please put the code in a "spoiler"? Link to comment Share on other sites More sharing options...
Gadgetto Posted January 3, 2020 Author Share Posted January 3, 2020 14 hours ago, szabesz said: Thanks! However, to make the thread readable, could you please put the code in a "spoiler"? Done - sorry I always forget this... 1 Link to comment Share on other sites More sharing options...
LostKobrakai Posted January 4, 2020 Share Posted January 4, 2020 On 1/2/2020 at 6:08 PM, Gadgetto said: Some fields like the documented field below in code (near the middle of the code), needs to be readonly in edit mode as not all parts of a SnipCart discount can be changed after creation. Why do you need to post values, which are no longer editable though? Should this not work just fine with the field disabled / not rendered as inoutfield? 1 Link to comment Share on other sites More sharing options...
Gadgetto Posted January 4, 2020 Author Share Posted January 4, 2020 7 hours ago, LostKobrakai said: Why do you need to post values, which are no longer editable though? Should this not work just fine with the field disabled / not rendered as inoutfield? The REST API of SnipCart requires this value with each POST or PUT request, but it may not be changed once submitted. Link to comment Share on other sites More sharing options...
flydev Posted January 5, 2020 Share Posted January 5, 2020 @Gadgetto maybe I have misread you and/or you didn't tested the technique I told you, check this demo : https://codepen.io/flydev/pen/ZEYvYKZ Link to comment Share on other sites More sharing options...
Gadgetto Posted January 5, 2020 Author Share Posted January 5, 2020 40 minutes ago, flydev said: @Gadgetto maybe I have misread you and/or you didn't tested the technique I told you, check this demo : https://codepen.io/flydev/pen/ZEYvYKZ Thanks for you input @flydev, I did check the technique you posted, but IMHO it's not very UX friendly. It first makes the user think that he can choose an option. I solved it in an easy way by disabling the select and an additional hidden field (as posted above). Link to comment Share on other sites More sharing options...
flydev Posted January 5, 2020 Share Posted January 5, 2020 https://codepen.io/flydev/pen/LYEeEdR this with a bit of css/js solve your issue. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now