I need to support my app for multiple languages and I want to provide the user a feature to select a language from a dropdown.
For now, I am working on the Firefox OS Boilerplate app and I have added a <select> in the homescreen as follows:
<p>
<label data-l10n-id="language">Language: </label>
<select id="language">
<option value="en">English</option>
<option value="fr">French</option>
<option value="es">Spanish</option>
</select>
</p>
I have also setup a simple event listener for it in vanilla JS.
I searched the MDN docs but I did not find anywere mentioned about switching the language.
Can you please guide me as in how to change the language in the Firefox OS app programatically?
One approach is the one you are using, let the user decide the language for the application. You could store the user's selection somewhere in the app (localStorage for example) and, when loading a page, check the language value and take the appropriate actions to show all text in that language. To implement this without using an external library you could have a global object with all the translations:
var translations = new Object();
translations.en = {
text1: 'The first text',
text2: 'The second text'
};
translations.es = {
text1: 'El primer texto',
text2: 'El segundo texto'
};
And your page looks like this:
<span data-translate="text1"></span>
<span data-translate="text2"></span>
So, after loading a page and having the language selected by the user in a variable (let's say lang), you iterate over all the elements that have the data-translate attribute and set their content dynamically.
var items = document.querySelectorAll('[data-translate]');
for (var i = 0; i < items.length; ++i) {
var index = items[i].getAttribute('data-translate');
items[i].innerHTML = translations[lang][index];
}
Another approach is using a library that detects the user's language automatically (from the system's language) and replaces all translatable elements from the page (you mark these) with the corresponding values (which are stored in a separate file). For example, check webL10n.
I believe you can implement the first approach more easily using webL10n, you should check it out.
Related
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>
...
);
}
}
I'm working on antd select and having issues with prepopulating it correctly, I can prepopulate the select box via its initialValue field decorator, however it populates strings, there does not appear to be a way to have a value (something I can work around but not ideal), and more importantly if the option is unselected/removed, it is no longer available in the select, unlike standard options. I can include in both select list options and initial value (as demonstrated in code below) but then it allows duplicate auto entry and it appears twice in the drop down list. Any ideas what I'm doing wrong?
Preperation of Preselected and Full Option List
let defaultSelect = [];
let selectList = [];
for (var a = 0; a < this.props.myData.length; a++) {
//push all options to select list
selectList.push(<Select.Option key={this.props.myData[i].id} >{this.props.myData[i].name}</Select.Option>)
//this is my code to pre-populate options, by performing a find/match
let matchedTech = _.find(this.props.myDataPrepopulate, { id: this.props.myData[i].id });
if (matchedTech) {
//notice I can push just the string name, not the name and the id value.
defaultSelect.push(this.props.myData[i].name);
}
}
Select Code
{getFieldDecorator(row.name, {
initialValue: defaultSelect
})(
<Select
tags
notFoundContent='none found'
filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
{selectList}
</Select>
)}
I think I understand your question, even if you posted code that doesn't run.
<Select.Option> works just like the plain html <select><option/></select>. In order to give the option a value it needs a value attribute, which is used to identify the option.
See http://codepen.io/JesperWe/pen/YVqBor for a working example.
The crucial part transformed to your example would become:
this.props.myData.forEach( data => {
selectList.push(<Select.Option value={data.id} key={data.id}>{data.name}</Select.Option>);
} );
defaultSelect = this.props.myDataPrepopulate.map( data => data.id );
(I took the liberty to use a bit more modern code patterns than your original)
There are several tricks for displaying different keyboards on mobile devices for HTML 5 inputs (i.e. <input> tags).
For example, some are documented on Apple's website, Configuring the Keyboard for Web Views.
These are great for usability, but when it comes to an input for for international postal codes (mostly numeric, but letters allowed), we're left with some poor options. Most people recommend using the pattern="\d*" trick to show the numeric keyboard, but that doesn't allow for letter input.
The type="number" input type shows the regular keyboard but shifted to the numeric layout:
This works well for iOS devices, but it makes Chrome think the input must be a number and even changes the input's behavior (up/down increment and decrement the value).
Is there any way to get iOS to default to the numeric layout, but still allow for alphanumeric input?
Basically, I want the iOS behavior for type="number" but I want the field to behave like a regular text field on desktop browsers. Is this possible?
UPDATE:
Sniffing the user-agent for iOS and using the type="number" input type is not an option. type="number" is not meant for string values (like postal codes), and it has other side effects (like stripping leading zeros, comma delimiters, etc) that make it less than ideal for postal codes.
Will this work?
HTML:
<input type="tel" pattern="[0-9]*" novalidate>
This should give you the nice numeric keyboard on Android/iOS phone browsers, disable browser form validation on desktop browsers, not show any arrow spinners, allows leading zeros, and allows commas and letters on desktop browsers, as well as on iPad.
Android / iOS phones:
Desktop:
iPad:
Browsers currently have no proper way of representing numeric codes like postcodes and credit card numbers. The best solution is to use type='tel' which will give you a number keypad and ability to add any character on desktop.
Type text and pattern='\d*' will give you a number keypad but only on iOS.
There is an HTML5.1 proposal for an attribute called inputmode which would allow you to specify keypad regardless of type. However not is not currently supported by any browser.
I would also recommend having a look at the Webshim polyfill library which has a polyfill method for these types of inputs.
A quick google search found this Stackoverflow question.
HTML
<input type="text">
Javascript
$('input[type="text"]').on('touchstart', function() {
$(this).attr('type', 'number');
});
$('input[type="text"]').on('keydown blur', function() {
$(this).attr('type', 'text');
});
The input type is switched before the form can be validated, showing the correct keyboard without messing up the value. If you only want it to run on iOS, you will probably have to use the user agent.
Stackoverflow on detecting iOS
An update to this question in iOS 11. You can get the number keypad by simply adding the pattern attribute (pattern="[0-9]*") to any input with a number type.
The following works as expected.
<input type="number" pattern="[0-9]*">
This also works.
<input type="number" pattern="\d*">
#davidelrizzo posted part of the answer, but the comments from #Miguel Guardo and #turibe give a fuller picture but are easy to miss.
This will make the numerical side of the ios keyboard display by default and maintains the ability to switch to the alphabetical side. When the html input type changes, the device changes the keyboard to match the appropriate type.
(function ($) {
var control = $('#test2');
var field = $('#test1');
control.bind('click', function () {
if (control.is(':checked')) {
field.attr('type', 'text');
} else {
field.attr('type', 'number');
}
})
}(jQuery));
<input type="number" id="test1" value="123" />
<input id="test2" type="checkbox" />Change
alternate demo: http://jsfiddle.net/davidcondrey/dbg1L0c0/3/embedded/result/
If you want the large numerical format keyboard (the telephone style) you can adjust the code accordingly and it still works:
(function ($) {
var control = $('#test2');
var field = $('#test1');
control.bind('click', function () {
if (control.is(':checked')) {
field.attr('type', 'text');
} else {
field.attr('type', 'tel');
}
})
}(jQuery));
<input type="tel" id="test1" value="a" />
<input id="test2" type="checkbox" />Change
You can use the native HTML API attribute called inputmode="numeric", inputmode="decimal". (This is the preferred way to implement it)
You can read further about input mode at the MDN here
<input type="number" inputmode="numeric" />
Try this:
<input type="text" name="postalcode" class="js-postal">
<script src="https://code.jquery.com/jquery-2.1.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
if('ontouchstart' in window) { // ensure we are in touch device.
$('input.js-postal').on('focus', function() {
var $this = $(this);
// memorize current value because...
var val = $this.val();
// this may cause reset value.
$this.attr('type', 'number');
setTimeout(function() {
// Asynchronously restore 'type' and value
$this.attr('type', 'text');
$this.val(val);
}, 0);
});
}
});
</script>
I know this is very hackish way, but this apparently works.
I haven't tested on Android devices though.
Note this may causes a little noticeable glitches when $this.attr('type', 'number') because this reset the value when input has non numerical characters.
Basic ideas are stolen from this answer :)
<input type="tel" inputmode="decimal">
Above has been working for me for several years. By working, I mean that on mobile devices, a numeric virtual keyboard is displayed when the input receives focus. On iOS devices, the keyboard allows users to enter numbers, decimals, and characters. My keyboard event handler inserts thousand separators, and there is no issue with passing validation, so I assume that users could also type in commas. Negative values can be entered, so hyphens are allowed, though I don't see a hyphen on the iOS keyboard.
If you would like to try this, you may try any calculator at my site.
Why not check the header of the HTTP request (user agent), and serve up the numeric layout to the iOS devices, while serving up the alphanumeric layout to the rest?
I have a classic asp page that has some select boxes on it. The boxes that are populated by a stored procedure that does not include an input parameter work fine.
My problem happens when I have a select box that I need to populate with a specific list of records. This is based on the current record the user has open, which I pass as a parameter to a stored procedure. I having the following code to call the SP:
'Return Possible RTA Contracts
Dim RecordsetApply
Dim RecordsetApply_cmd
Dim RecordsetApply_numRows
Set RecordsetApply_cmd = Server.CreateObject ("ADODB.Command")
RecordsetApply_cmd.ActiveConnection = GLData_connection_STRING
RecordsetApply_cmd.CommandText = "return_rtacontractlist"
RecordsetApply_cmd.CommandType = adCmdStoredProc
RecordsetApply_cmd.Parameters.Append RecordsetApply_cmd.CreateParameter("ContractIDParam", adVarChar, adParamInput, 50)
RecordsetApply_cmd("ContractIDParam") = RecordsetContract__GLColParam
Set RecordsetApply = RecordsetApply_cmd.Execute
RecordsetApply_numRows = 0
This works fine as far as the select box populating with the correct data, but the rest of the page HTML stops rendering. Here is the code for the select box:
<td><span id="sprytextfield24">
<select style="font-size:12px" name="rtacontract" id="rtacontract">
<%
While (NOT RecordsetApply.EOF)
%>
<option value="<%=(RecordsetApply.Fields.Item("ContractID").Value)%>"><%=(RecordsetApply.Fields.Item("ContractDesc").Value)%></option>
<%
RecordsetApply.MoveNext()
Wend
If (RecordsetApply.CursorType > 0) Then
RecordsetApply.MoveFirst
Else
RecordsetApply.Requery
End If
%>
</select><br />Apply Remainder To*<br />
<span class="textfieldRequiredMsg">Field Required</span></span></td>
If I remove the parameter and actually hard code the record in the SP then the page loads normally. Of course this wont work as a solution though.
Hoping this is a simple mistake I have made since I am fairly new to this.
The server side code itself look fine. Most likely the data you get is "breaking" the HTML (e.g. containing raw HTML) so better encode it to be on the safe side:
<option value="<%=Server.HTMLEncode(RecordsetApply.Fields.Item("ContractID").Value)%>"><%=Server.HTMLEncode(RecordsetApply.Fields.Item("ContractDesc").Value)%></option>
This question already has answers here:
Dynamic controlgroup and checkboxes unstyled
(6 answers)
Closed 8 years ago.
This is my code:
http://jsfiddle.net/YKvR3/34/
I would create a controlgroup with values that are in my array (name).
The problem is that when I click load button the values are added in a controlgroup but the jquery-ui styles are not loaded like in the image.
The controlgroup is not styled with jquery-ui mobile css.
$("#load").click(function(){
var name=["one","two"];
var html='<fieldset id="listPlayers" data-role="controlgroup"><legend><h1>Choose as many players as youd like to remove:</h1></legend>';
for ( var int = 0; int < 2; int++) {
html+='<input type="checkbox" name="checkbox-'+int+'a" id="checkbox-'+int+'a" class="custom" /><label for="checkbox-'+int+'a">'+name[int]+'</label>';
}
alert('<legend><h3>Choose as many players as you would like to remove:</h3></legend>'+html+'</fieldset');
$("#list").html(html+'</fieldset');
//$("#list").page();});​
What I am doing wrong?
Thanks.
$("#list").trigger('create');
From: jqm docs
if you generate new markup client-side or load in content via Ajax and inject it into a page, you can trigger the create event to handle the auto-initialization for all the plugins contained within the new markup. This can be triggered on any element (even the page div itself), saving you the task of manually initializing each plugin (listview button, select, etc.).
I do applogies if this post is too old and if my post isn't by the correct standard since it's the first time ever posting so please correct me if it's horribly bad :-]
But in case someone else comes across it, I had similar problems with how the dynamic data is displayed and I used the jsfiddles and comments above as a help, and this is what got mine to work, well somewhat near my solution, I don't have a button to load the data it's loaded automatically when the page is loaded.
Updated In my .html-file:
<div id="members"></div>
<input type="button" id="load" value="test"/>
Updated In my .js-file:
$("#load").click(function(){
var name = ["NameOne","NameTwo", "NameThree"];
var fset = '<fieldset data-role="controlgroup" id="members-ctrlgroup"><legend>This is a legend:</legend>';
var labels='';
for ( var i = 0; i < name.length; i++) {
labels += '<input type="checkbox" class="checkbox" id="c'
+ i
+ '"><label for="c'
+ i
+ '" data-iconpos="right">'
+ name[i]
+'</label>';
}
$("#members").html(fset+labels+'</fieldset>');
$("#members").trigger("create");
});
I know the "field" looks a bit weird how I divided it but I find it somewhat easier when it comes to getting the whole html-string correct in these cases.
Updated In order to have the rounded corners and have it as one controlgroup you'll have to have this approach instead. Just like the former posters showed.
Do note that the id with the checkbox and the label for= can tend to screw the output if they're not the same :-]
fiddle
In order to replace the content you should use .html(); instead of .append(), which adds the new content after the existing one.
After adding content to a jQuery Mobile Page you need to enhance the content, using for instance $("input[type='radio']").checkboxradio();
I was using
for( var i=0 ; i < html.length ; i++ ){
var spline = html[i].split("|");
inHTML = inHTML + " <input type=\"checkbox\" name=\"checkbox-"+i+"a\" id=\"checkbox-"+i+"a\" class=\"custom\" /> <label for=\"checkbox-"+i+"a\">"+ spline[0] +" , "+ spline[2] +"</label> ";
}
jq("fieldset#myFieldSet").empty();
jq("fieldset#myFieldSet" )
// Append the new rows to the body
.append( inHTML )
// Call the refresh method
.closest( "fieldset#myFieldSet" )
// Trigger if the new injected markup contain links or buttons that need to be enhanced
.trigger( "create" );