How to sync form and useState object? - forms

How do I link a graph using a state to a form, so when the form changes the graph is automatically updated as well, even the form is not submitted yet? The graph is just using showCarrot to generate a chart.js element.
I found initialValues as fields for forms but do not know how to clue this all together. Anyone can help to save me from insanity?
Update: I figured that Ant Design form is based on field-form, still not know how this helps but it is a trail.
That's the state I set and propagate to my form and my graph
const [showCarrot, setCarrot] = useState<ICarrotArray>([]);
That's my form and table to edit the data
<Form form={form} initialValues={showCarrot} onFinish={onFinish}>
<Table
dataSource={showCarrot}
rowKey={"id"}
pagination={false}
bordered
footer={(): React.ReactElement => {
return (
<Button onClick={addCarrot}>
<PlusOutlined /> Add Carrot
</Button>
);
}}
>
...
</Table>
<br />
<Row justify="end">
<Form.Item>
<Button type="default" onClick={onReset}>
Restore
</Button>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" style={{ marginLeft: 8 }}>
Save
</Button>
</Form.Item>
</Row>
</Form>

Firstly I just want to understand, correct me if I'm wrong.
You set your initialValues for form which is showCarrot. Is it mean that initialValues set for some Form.Item, because usually object element inside initialValue is used as data for Form.Item by their name.
Like so
<Form
name="validate_other"
{...formItemLayout}
onFinish={onFinish}
initialValues={{
['input-number']: 3, //name of the Form.Item
['checkbox-group']: ['A', 'B'],
rate: 3.5,
}}
>
<Form.Item label="InputNumber">
<Form.Item name="input-number" noStyle>
<InputNumber min={1} max={10} />
</Form.Item>
<span className="ant-form-text"> machines</span>
</Form.Item>
But by your code it look you want set showCarrot only as table data. If so, I can't find columns in your table, look like currently error because of that. You should add there dataIndex param which will listen for your data elements by that name

Related

AMP autocomplete how get id from autocomplete results and display only text in input

view screen I am using https://amp.dev/documentation/components/amp-autocomplete/ and I am able show in results id and name concated in one string, but I need show only name and store id in hidden input.
code screen
<amp-autocomplete filter="substring" filter-value="name" min-characters="2" src="/ajax/get_active_clinics.php" class="name_autocomplete">
<input type="text" placeholder="Numele clinicii" name="clinic_name" id="clinic_name"
{literal}on="change:AMP.setState({clinic_name_validation: true, form_message_validation:true})"{/literal}>
<span class="hide"
[class]="formResponse.clinic_name && !clinic_name_validation ? 'show input_validation_error' : 'hide'">Clinica este obligatorie</span>
<template type="amp-mustache" id="amp-template-custom">
{literal}
<div class="city-item" data-value="ID - {{id}}, {{name}}">
<div class="autocomplete-results-item-holder">
<div class="autocomplete-results-item-img">
<amp-img src="{{link}}" alt="{{name}}" width="40" height="40"></amp-img>
</div>
<div class="autocomplete-results-item-text">{{name}}</div>
</div>
</div>
{/literal}
</template>
</amp-autocomplete>
You can use the select event on amp-autocomplete to get the event.value which will return the value of the data-value attribute of the selected item.
https://amp.dev/documentation/components/amp-autocomplete/#events
You can then call the split() string method on the result.
You'll need to modify the data-value in your mustache template like so:
<div class="city-item" data-value="{{id}},{{name}}">
Then add the following code to your autocomplete, this will assign the split values to 2 temporary state properties.
<amp-autocomplete
...
on="select: AMP.setState({
clinicName: event.value.split(',')[0],
clinicId: event.value.split(',')[1]
})"
>
Once these values are in state you can then access them using bound values. Note the [value] attribute, this will update the inputs value when state changes. It's worth mentioning that the change in value won't trigger the change event listener on your input here as it's only triggered on user interaction.
<input
type="text"
placeholder="Numele clinicii"
name="clinic_name"
id="clinic_name"
[value]="clinicName"
on="change:AMP.setState({
clinic_name_validation: true,
form_message_validation:true
})"
/>
Last thing you'll need to do is add the hidden input for Clinic ID, again this will need to be bound to the temporary state property clinicId.
<input
type="hidden"
name="clinic_id"
[value]="clinicId"
>

Whenever I apply autocomplete.js the input text box will change Algolia

Im using algolia to perform a search on my website, but I realized one thing. Im using search box generator to customized my search input field. However the problems occur, when I try to apply autocomplete.js on my search input field
Initially, it looks like the one below,
but when I apply the autocomplete feature it will look like this
Code - HTML
<form id="search" novalidate="novalidate" onsubmit="return false;" class="searchbox sbx-google" style="margin-top: 7px;">
<div role="search" class="sbx-google__wrapper">
<input type="search" id="search_input" name="search" placeholder="Search" autocomplete="off" required="required" class="sbx-google__input">
<button type="submit" title="Submit your search query." class="sbx-google__submit">
<svg role="img" aria-label="Search">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-search-13"></use>
</svg>
</button>
<button type="reset" title="Clear the search query." class="sbx-google__reset">
<svg role="img" aria-label="Reset">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-clear-3"></use>
</svg>
</button>
</div>
</form>
Code - JAVASCRIPT
autocomplete('#search_input',
{ hint: false }, {
source: autocomplete.sources.hits(index, {hitsPerPage: 5}),
//value to be displayed in input control after user's suggestion selection
displayKey: 'name',
//hash of templates used when rendering dataset
templates: {
//'suggestion' templating function used to render a single suggestion
suggestion: function(suggestion) {
console.log(suggestion)
return '<span>' +
suggestion._highlightResult.title.value + '</span>';
}
}
});
The custom search box is advised by algolia themselves, on the autocomplete documentation. I have no idea on how to solve this problem, seems like the js script overwrite the css styling. This only happen if I passed in the #search_input in the autocomplete function
Here is the js fiddle https://jsfiddle.net/Ldpqhkam/
Algolia autocomplete adds a span around the input and that's what breaks the design. It has inline style changing the display, you can override it to fix the design.
.algolia-autocomplete {
display: inline !important;
}

Real time update between 2 components?

Is it possible to have a realtime update of input fields between two components?
In a component I have an input field which has a v-model="value". I wanna pass that input realtime to the other component and fill it into that input field.
Data of inputValue should be passed to the component 2 as value props. Or maybe I'm wrong with my result?
COMPONENT 1
<template>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" id="global-{{element}}" v-model="inputValue">
<label class="mdl-textfield__label" for="global-{{element}}">{{ label }}</label>
</div>
</template>
COMPONENT 2
<template>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input name="items[{{prop1}}][{{element}}]" value="{{value}}" class="mdl-textfield__input"
type="text" id="{{element}}">
<label class="mdl-textfield__label" for="{{element}}">{{ label }}</label>
</div>
</template>
<script>
export default{
props: ['prop1', 'element', 'value', 'label']
}
</script>
I tried with ...
this.$dispatch('tag-update', this.inputValue);
... but I need an #keyup.xx. But that's not what I want. I want it to update as soon as I pressed and released a letter, number etc.
You can certainly achieve this with events, or you can move the inputValue up to the parent component or root and pass it to each component as a synced prop.
http://jsfiddle.net/gtmmeak9/118/
The second component doesn't have to be synced if you just want one way binding on it.

About the $dirty property and getting only modified fields in a form

I have a form with few fields and I'm trying to get modified fields only.
Here is what I got so far (simplified version) :
<form name="formTicket">
<div class="item title">
<label for="category-assignation"><?php echo T::_("Assignation :")?></label>
<textarea type="text" name="assignation" cols="50" rows="4" id="category-assignation" data-ng-model="ticket.assignation"></textarea>
</div>
<div class="item title">
<input id="save" type="submit" value="Save" data-ng-click="saveTicketInfo()" />
</div>
</form>
In my controller.js, I have :
$scope.saveTicketInfo = function() {
console.info($scope.ticket);
console.info($scope.formTicket);
//Query to my service to save the data
Category.saveInfo.query({data: $scope.ticket});
};
Prior to AngularJs, I would save my fields in an array at the loading of my form and compare their values with the new values posted. I could still do this but I'm looking for an AngularJs approach.
I've been trying to use the $dirty property of each field and only send to my services those with "true" value but this behavior is not suitable for me : if the defaut value for my field is "test" and the user modify the input to "test2" and modify it back to "test" and post it, $dirty will be true (even if the value has not really changed).
Is there any convenient and optimal way to achieve what I want ?
Thank you for your time.

Persisting JSF2 Composite Component value

I have a datatable which loops through a List and has a value column which renders as such:
<h:dataTable var="assessmentFieldValue" value="#{assessmentBean.assessmentFieldValues}">
...
<ui:fragment rendered="#{assessmentFieldValue.field.type eq 'TEXT'}">
<h:inputText value="#{assessmentFieldValue.value}" />
</ui:fragment>
<ui:fragment rendered="#{assessmentFieldValue.field.type eq 'SLIDER'}">
<component:slider value="#{assessmentFieldValue.value}" />
</ui:fragment>
...
</h:dataTable>
So sometimes I get a standard inputText, sometimes I get my composite slider component:
<composite:interface>
<composite:attribute name="value" />
</composite:interface>
<composite:implementation>
<script type="text/ecmascript">
function updateValue(value) {
$('##{cc.id} span').each(function() {
$(this).text(value);
});
}
</script>
<div id="#{cc.id}">
<input id="sliderComponent" type="range" min="1" max="10"
value="#{cc.attrs.value}"
style="float: left"
onchange="javascript:updateValue(this.value);" />
<h:outputText id="fieldValue" value="#{cc.attrs.value}"
style="min-width: 20px; display: block; float: left" />
</div>
</composite:implementation>
This all renders as I would like it too (deployed on JBoss-AS7), but when I hit the save button associated with the datatable the assessmentBean.assessmentFieldValue List doesn't reflect any value changes on the slider component yet it does for the standard inputText.
Can anyone suggest why changes to the slider aren't making it back to the backing bean? Thanks!
That's because you used a plain HTML <input> element instead of a fullworthy JSF input component like <h:inputText>. This way the value is in no way bound to the JSF context. It's only treated as plain vanilla template output value, not as input value. A composite component isn't going to solve this. You really need to create a fullworthy UIComponent for this (or to look for a 3rd party component library which has already done the nasty job for you, such as PrimeFaces with its <p:slider>).
See also:
When to use <ui:include>, tag files, composite components and/or custom components?