Focus issue when text inputs are used in a template repeat - dart

Input texts are inserted in the DOM using an iterable repeat like the following:
HTML:
<template repeat="value in listValue">
<input type="text" bind-value="listValue[$index]">
</template>
Dart:
List listValue = toObservable(["value one", "value two"]);
There is a problem with the focus: when a letter is typed in any of the input field, the DOM is redisplayed and the focus is lost. This is due to focus bug
How could I have this working?

The focus problem is a result that WebUI currently considers changes to individual entries in a list as a general change to the list itself, so it re-renders the entire template-repeat on every edit. You can get the behavior you want by adding one level of indirection. The idea here is to make it easier to distinguish changes to values from changes to the list.
For instance, instead of having list of string values, make it a list of observable references to string values, as follows:
html:
<template repeat="value in listValue">
<input type="text" bind-value="value.value">
</template>
dart:
import 'package:web_ui/web_ui.dart';
List listValue = toObservable([]);
void main() {
listValue.add(new ObservableReference("value one"));
listValue.add(new ObservableReference("value two"));
}

Related

Svelte input binding breaks when a reactive value is a reference type?

(I'm new to Svelte so it is quite likely that I'm doing something wrong here)
UPDATE: I've added a second, slightly different REPL which may demonstrate the problem better. Try this one: https://svelte.dev/repl/ad7a65894f8440ad9081102946472544?version=3.20.1
I've encountered a problem attempting to bind a text input to a reactive value.
I'm struggling to describe the problem in words, so hopefully a reduced demo of the issue in the attached REPL will make more sense.
https://svelte.dev/repl/6c8068ed4cc048919f71d87f9d020696?version=3.20.1
The demo contains two custom <Selector> components on a page.
The first component is passed two string values ("one" and "two"):
<Selector valueOne="one" valueTwo="two"/>
Clicking the buttons next to the input field sets selectedValue to one of these values.
This, in turn, triggers the following reactive declaration to update:
$: value = selectedValue
The input field is bound to this reactive value:
<input type="text" bind:value>
So clicking the "One" button sets the input text to "one", and clicking the "Two" button sets the input field to "two".
Importantly though, you can still type anything into the input field.
The second component is passed two array values:
<Selector valueOne={[1, "one"]} valueTwo={[2, "two"]}/>
Again, clicking the buttons sets selectedValue to one of these.
However this time the reactive declaration depends on an array element:
$: value = selectedValue[1]
Everything works as before, except now you can no longer type into the input field at all.
So the question is - why does <input bind:value> behave differently for these two:
$: value = aString
vs
$: value = anArray[x]
It seems that this is only an issue when using two-way bindings.
By switching to a one-way and an on:input handler, the problem goes away:
i.e. instead of this:
<input type="text" bind:value={valX}/>
use this:
<input type="text" value={valX} on:input={e => valX = e.target.value}/>
I'm pretty sure your reactive declaration is overwriting your bound value as soon as it changes, which is with every key stroke on the input and every button press. Meaning it technically is working, you're just reverting it each time it changes. Check out this version of it that uses a watcher.
Also binding to a reactive declaration means you're never actually changing the variables with the input (which you can see in your JSON result on the first selector when you type in the input the value doesn't update only on button click).
Why not lose the reactive declaration and bind directly to the variable you want. Then use an {#if} block to switch between which version of the input you're showing based on the truthiness of index?
<script>
export let valueOne;
export let valueTwo;
export let index;
let selectedValue = index? [] : '';
let selectValue = (val) => selectedValue = val;
</script>
{#if index}
<input type="text" bind:value={selectedValue[index]} placeholder="Type anything...">
{:else}
<input type="text" bind:value={selectedValue} placeholder="Type anything...">
{/if}
<button on:click={() => selectValue(valueOne)}>One</button>
<button on:click={() => selectValue(valueTwo)}>Two</button>
<p>
<strong>Selected value:</strong> {JSON.stringify(selectedValue)}
</p>
By binding directly to the selectedValue or an index of it you have the added benefit of changing the value with the input. Here's a working example in the REPL

New to React: Why is one array treated differently than the other?

I'm working on a React app that is fed data from a Rails api. I'm currently working on a form that includes a nested association (i.e. in the model_a has many model_b's and you can create them in the same form).
The problem I'm having is that Rails expects nested association with a certain naming convention and the same field that controls how the parameter is named when its sent to rails also controls how React finds the right data when the Rails API responds.
This becomes problematic on the edit page because I want to show the models_a's (Retailers) already existing model_b's (SpendingThresholds in this case) and when I change the 'name' field to suit the rails side, React doesn't know where to look for that data anymore. When I try to pass the data directly it comes in as a different type of array and certain functions fail.
I think its easier to show than tell here so
initially I had this
<FieldArray
name="spending_thresholds"
component={renderSpendingThresholds}
/>
and data was coming through like
Object {_isFieldArray: true, forEach: function, get: function, getAll: function, insert: function…
to my React app from the Rails API, which worked, however that 'name' isn't to Rails liking (Rails wants it to be called 'spending_thresholds_attributes' for accepts_nested_attributes to work) so I changed it to
<FieldArray
name="spending_thresholds_attributes"
fields={this.props.retailer.spending_thresholds}
component={renderSpendingThresholds}
/>
and data start coming through to the renderSpendingThresholds component in this format
[Object]
0:Object
length:1
__proto__:Array(0)
which React doesn't like for some reason.
Anyone know how to fix this/why those two objects, which hold the same information from the Rails side anyway, are being treated differently?
EDITS
renderSpendingThresholds component
The fields attribute in the renderSpendingThresholds component is the object that's coming through differently depending on how I input it
const renderSpendingThresholds = ({ fields }) => (
<ul className="spending-thresholds">
<li>
<Button size="sm" color="secondary" onClick={(e) => {
fields.push({});
e.preventDefault();
}
}>
Add Spending Threshold
</Button>
</li>
{fields.map((spending_threshold, index) => (
<li key={index}>
<h4>Spending Threshold #{index + 1}</h4>
<Button
size="sm"
color="danger"
title="Remove Spending Threshold"
onClick={() => fields.remove(index)}
>
Remove
</Button>
<Field
name={`${spending_threshold}.spend_amount`}
type="number"
component={renderField}
label="Spend Amount"
placeholder="0"
/>
<Field
name={`${spending_threshold}.bonus_credits`}
type="number"
component={renderField}
label="Bonus Credits"
placeholder="0"
/>
</li>
))}
</ul>
);
It looks like you are passing fields through props and then destructuring the fields out of the props in the callback of the renderSpendingThresholds and discarding the rest. According to the docs, a specific redux-form object is passed through to the render callback. You're essentially overwriting this. Try changing {field} to something like member or spending_threshold. Then you can use the specific map function to iterate over the spending_threshold items. Your field prop should still be available under member.fields or something similar.
For the code that you currently show, who exactly handles the submission?
you use the original flow of form submit?
if so, so please handle that by yourself.
** this line of code, looks weird:
onClick={() => fields.remove(index)}
as you interact directly with the state values...
you need to update the state through
this.setState({fields: FIELDS_WITHOUT_ITEM})
and now when you need to handle your own submission, you don't really care of the input names. Because you are using the state as input.
ie:
class FormSpending extends Component {
handleSubmit() {
var fieldsData = this.state.fields.map(field => {
return {
whateverkey: field.dontcare,
otherKey: field.anotherDontCare
};
});
var formData = {
fields: fieldsData
};
ajaxLibrary.post(URL_HERE, formData).....
}
render() {
return (
...
<form onSubmit={()=>this.handleSubmit()}>
...
</form>
...
);
}
}

Imposible to use core-a11y-keys with Inputs

Dart, Polymer 0.5, Dartium.
In a page I have some div element with core-a11y-keys inside, keys are "up down left right". It works perfectly, some actions are happened after key down.
Also I have input field on the page. And problem is I can't use arrow keys in it because of core-a11y-keys.
Question is: how to avoid destruction behavior?
HTML:
<body>
<div id="widgetContainer">
<core-a11y-keys target="{{body}}" keys="up down left right"
on-keys-pressed="{{widgetContainer_on_move_keys}}">
</core-a11y-keys>
</div>
<input id="txtInput">
</body>
Make sure that the target attribute of core-a11y-keys is in fact present and targeting the div, otherwise it will apply to the whole page including your input. See here for more detail on how to do that: https://groups.google.com/a/dartlang.org/forum/m/#!topic/web/k8Wzj6KCfgM
If your input was a child of the div that your core-a11y-keys was targeting, it would be doing what you instructed it to do anywhere in that div: intercepting keystrokes. In that case, you would need to handle the onKeyPress event in the input like <input on-keypress="{{handleInputKeyStrokes}}">:
handleInputKeyStrokes(Event e) {
// You'll need one or both of these; not sure which.
e.preventDefault();
e.stopPropagation();
}
I haven't tried this, and it may be that you need onKeyUp and onKeyDown instead, as in https://stackoverflow.com/a/13746419.

TableSorter : how to export results to csv?

TableSorter is a great jquery script to sort html tables with many options.
But I don't know how to add a simple 'export to csv' button (or link) to get a file containing the records of my table (with no special formatting).
I know the Output Plugin but it seems far too complex to me.
Thanks by advance for your help !
Ted
It's actually not complicated, it only looks intimidating because of all the options. The output widget can output csv, tsv, any other separated (space, semi-colon, etc) values, javascript array or JSON.
If you are just using basic functionality, the default settings will:
Output csv to a popup window
Only include the last header row
Only include filtered rows (so all rows if the filter widget isn't even being used)
Will only output the table cell text (ignores HTML)
All you would need is this code (demo):
HTML
<button class="download">Get CSV</button>
<table class="tablesorter">
....
</table>
Script
$(function () {
var $table = $('table');
$('.download').click(function(){
$table.trigger('outputTable');
});
$table.tablesorter({
theme: 'blue',
widgets: ['zebra', 'output']
});
});
I created another demo, showing all options, with a set of radio buttons which allow the user to choose between sending the output to a popup window, or downloading the file.
HTML
<label><input data-delivery="p" name="delivery" type="radio" checked /> popup</label>
<label><input data-delivery="d" name="delivery" type="radio" /> download</label>
<button class="download">Get CSV</button>
Script
var $table = $('table');
$('.download').click(function(){
// get delivery type
var delivery = $('input[name=delivery]:checked').attr('data-delivery');
$table.data('tablesorter').widgetOptions.output_delivery = delivery;
$table.trigger('outputTable');
});
So, you can make it as simple or complex as you want (see the actual output widget demo which allows the user to set almost all the options).

Dynamically bind (or format) two #observable variables to a third #observable variable

Here's something I thought might be a bit easier. Despite the specifics of the question, I'm interested in any method that will let me have a third form field auto-updated based on the content of two other fields with Polymer.dart.
Something like this, where the "[ ]" represent form fields.
Name: [given name] [family name]
Full name: [family_name, given_name]
So for example; if someone enters "John" and "Smith" in the first two fields. Then the "full name" line shows: [Smith, John], when either of the fields are updated.
I've based the following example on the classes and mark-up from the form Dart Polymer tutorial
Get Input from a Form tutorial
For a form like this ...
<polymer-element name="reference-form" extends="form" >
<template>
<style> ... </style>
<div id="slambookform" >
<div class="entry">
<label>Author:</label>
<input type="text" value="{{theData['authorGivenName']}}" >
<input type="text" value="{{theData['authorFamilyName']}}">
</div>
:
<div class="entry">
<label>Full name:</label>
<input disabled type="text" value="{{fullName}}" >
</div>
:
</div>
<template>
</polymer-element>
My initial attempt to make this happen was a function like:
#observable
String fullName(){
return theData['authorFamilyName'] +', '+ theData['authorGivenName'];
}
Which doesn't work. When I make 'fullName' to an #observable variable and update it with a button the form is updates as required. Hence my question, can I bind a third field to two (or more) others?
I think I will need some kind of event handler. For two fields, formatting on a change even is simple enough. I want to format several fields in the ultimate case, not just two fields.
While on this topic, is there a hook in dart-polymer or dart to supply a future or call-back? In my example, something like: 'after-change'. Just thinking out loud, something like that would be good.
Thanks in advance.
Along those lines (caution - code is not tested)
<polymer-element name="reference-form" extends="form" >
<template>
<style> ... </style>
<div id="slambookform" >
<div class="entry">
<label>Author:</label>
<input type="text" value="{{authorGivenName}}" >
<input type="text" value="{{authorFamilyName}}">
</div>
:
<div class="entry">
<label>Full name:</label>
<input disabled type="text" value="{{fullName}}" >
</div>
:
</div>
<template>
</polymer-element>
class reference_form.dart
String _authorGivenName;
#observable get authorGivenName => _authorGivenName;
set authorGivenName(String val) {
_authorGivenName = val;
notifyPropertyChange(#fullName, '${_authorGivenName} ${_authorFamilyName}',
'${val} ${_authorFamilyName}');
}
String _authorFamilyName;
#observable get authorFamilyName => _authorFamilyName;
set authorFamilyName(String val) {
_authorFamilyName = val;
notifyPropertyChange(#fullName, '${_authorGivenName} ${_authorFamilyName}',
'${_autorGivenName} ${val}');
}
#observable
String get fullName => '${_authorGivenName} ${_authorFamilyName}';
I have a workaround for this problem, standing on the shoulders of Günter Zöchbauer (comment above). My objective is to "bind" one field value to two in a read-only fashion. We are not quite there yet, however the pathway is educational in its own right.
Observer method
This solution is kind of a workaround for the objective I set myself. I've made some annotations on this code to explain what I saw, or why I think is happening.
The intention is for fullName to show both names in the form:
familyName, givenName; e.g.
Smith, John
reference-form.html:
<polymer-element name="reference-form" extends="form" >
<template>
<style> ... </style>
<div id="slambookform" >
<div class="entry">
<label>Author:</label>
<input type="text" value="{{theData['givenName']}}" >
<input type="text" value="{{familyName}}">
</div>
:
<div class="entry">
<label>Full name:</label>
<input disabled type="text" value="{{fullName}}" >
</div>
:
</div>
<template>
</polymer-element>
The code for the form properties, the things Polymer-dart binds to the HTML with the moustache syntax, "{{fullName}}". To keep things simple, I used just one 'notifier' field and this updates the fullName field from both familyName and givenName.
reference_form.dart:
//---- testing ----
String _familyName; // (1)
#observable // (2)
String get familyName => _familyName; // (3)
void set familyName( String nam ){ // (4)
_familyName = nam;
fullName = notifyPropertyChange( // (5)
#fullName,
"${fullName}",
"${nam}, ${theData['givenName']}" );
}
#observable
String fullName; // (6)
//---- end: testing ----
The private member, "_familyName", is a shadow for the public familyName property used in the template (snippet above).
Shadow (private) member, "_familyName", stores the data for the familyName pseudo property.
The next three lines declare an #observable property, familyName
Get familyName. Simply echo the value for the shadow variable.
Set familyName. Updates the shadow variable and the composite fullName property.
Note: the composit formatting could be done with two lines: _familyName = nam; fullName = nam; ... But we want to see all changes propagated see (#5).
The notifyPropertyChange() method updated all observers of the fullName property.
Note: I didn't hack around inside Polymer itself; inside the Observable class, fullName doesn't has no observers with the code shown.
Until I saw this, I assumed that the Polymer binding to the HTML template was via an observer (watcher), it would seem not. I may be mistaken. In any case, the call to notifyPropertyChange() for the '#fullName' symbol didn't change the results for this test case.
fullName property bound to the Polymer form.
Basically the {{fullName}} value will be updated every time there's a change to the familyName pseudo property.
Note on efficiency:
The familyName setter is called with every keystroke (observed while debugging). I understand that, and suggest it is not always really the best solution.
For me, I'd prefer to only call the setter when a user exits the field. However when I used onblur, the trigger was a blur of the form, not the field.
It seems that we might all benefit in terms of performance with a bit more insider information about these hooks, pathways and any options available to make things more efficient.
Comments and improvements welcome. This example is a workaround for me, so its definitely a work in progress. ;-)
Encapsulation method
I am evolving a solution closer to the original ambition and based on the 'observer method' above. This approach relies on the current, i.e. Dart v4, use of modules and libraries. I'll show the working code first and explain interesting stuff with notes.
reference_form.dart:
import 'package:exportable/exportable.dart'; // [1]
class _Data // [2]
extends Object with Exportable { // [3]
#export String publishDate; // [4]
#export String authorGivenName = '(given)';
#export String authorFamilyName = '(family)';
#export String authorUrl = '';
//--- attributes ---
String get fullName => "${authorFamilyName}, ${authorGivenName}"; // [5]
void set fullName( String nam ){ // [6]
//don't need this
}
//--- ctor ---
_Data(){
publishDate = new DateTime.now().toString(); // [7]
}
} //_Data
#CustomTag('reference-form')
class SlamBookComponent extends FormElement with Polymer, Observable {
SlamBookComponent.created() : super.created();
//---- testing ----
#observable
_Data data = new _Data(); // [8]
:
} //SlambookComponent
Notes:
Include Exportable mixin to convert to JSON. I'm not exporting 'fullName' because it is just formatting at the moment.
Add exportable to your pubspec.yaml and 'Run Pub get'.
The "_Data" class is private to the reference_form.dart module. I did a bit of testing of the scope rules because I do not want the internal data structure to leak, except for something catholic like JSON of course (small-c).
Bring-in the Exportable mixin.
I have tested Exportable, it implements exactly what I thought I'd have to write myself. Happy with this.
JSON is not a requirement of the original question; but I did want the (eventual) solution to be a first class artefact that can be serialized or saved is important in the majority of my use-cases.
This is a very good example of the facility to extend Dart quick and agile!
Use the #export modifier to identify fields specific to be interchanged as JSON.
Export the fullName attribute as a String (get).
There is no need for set operation. However Dart apparently insists that a Set method matches 'get'.
I am disappointed by this. I much prefer the idea that I can have READ-ONLY properties and attributes, e.g. like ruby.
As tested, Dart SDK v1.4.0; fails when a matching setter is not implemented/declared(??).
Use a constructor to set initial values for Date data attribute.
Declares an opaque public property called "data", as an (private) _Data instance.
The data formatting of key fields is encapsulated in the private _Data declaration.
The Exportable mixin interface is used to map the private class to a public JSON result.
Point #8 demonstrates a powerful aspect of dart, to enable an opaque implementation of objects and yet, you can 'deliver'/'share' details without specific internal details.
I have run this code and checked that the concepts work for hidden data (the _Data type) and opaque access and serialisation. Also you can't accidentally look at internal private type (accidentally, although explicit hacks may be possible). I don't apologise for accepting the C / C++ conscious responsibility paradigm -- I think this a the most powerful aspect of being a programmer; WE are responsible for effects/bugs stemming from the code we produce. I recommend testing 'bits of behaviour' in small mini-use-cases.
I put examples of the polymer markup; nothing surprising. For me this approach is less verbose and a bit more Object Oriented than the original (early) Dart tutorial
reference_form.html
<polymer-element name="reference-form" extends="form" >
<template>
<style> ... </style>
<div id="slambookform" >
<div class="entry">
<label>Author:</label>
<input type="text" value="{{data.authorGivenName}}" >
<input type="text" value="{{data.authorFamilyName}}">
</div>
<div class="entry">
<label>Published:</label>
<input type="date" value="{{data.publishDate}}">
</div>
</div>
</template>
<script type="application/dart" src="reference_form.dart"> </script>
</polymer-element>
In the Polymer mark-up can know (and has visibility over) internal field names. Why?
... Because the "reference_form.html" and "reference_form.dart" via Polymer-dart. It is quite nice really; although it seems that the ".dart" and ".html" components are closely coupled like ASP.NET and C#/VN.NET as (also) specified by convenience(??). I confess that's a completely different subject; there are things to resolve to keep things yar (yachting term).
Anyway for me, I feel the approach begun with the encapsulation shamble above is better suited to my needs for a small utility.
Polymer now supports this use case directly with #ObserveProperty
#observable String authorGivenName = '';
#observable String authorFamilyName = '';
#observable String get fullName => '${authorGivenName} ${authorFamilyName}';
#ObserveProperty('authorGivenName authorFamilyName')
void updateFullName(old) {
notifyPropertyChange(#fullName, old, fullName);
}

Resources