How can I validate if EditText has setError enabled ?
I want to disable a button if EditText has an error.
Any other way to achieve this.
It kinda works when I put view.calcbutton.setEnabled(false) inside the validateEditText-function, but I use the validateEditText-function to validate multiple EditTexts and only the last function-call disables the button.
if the first function-call disables the button, the second enables it again, and vice versa.
But I want do it outside this function because if one of the multiple EditTexts has setError the button should be disabled.
//global var blockcalcbutton
var blockcalcbutton = 0
//function to validate EditTexts and set blockcalcbutton=1 if setError
validateEditText(view.input_volt, view, getString(R.string.invalid_volt))
if(blockcalcbutton == 1) {
view.calcbutton.setEnabled(false)
view.calcbutton.setText(getString(R.string.calcbutton_disabled))
view.calcbutton.setBackgroundResource(R.color.buttonDisabled)
} else {
view.calcbutton.setEnabled(true)
view.calcbutton.setText(getString(R.string.calcbutton_enabled))
view.calcbutton.setBackgroundResource(R.color.buttonBackground)
}
fun validateEditText(editText: EditText, message: String) {
val myEditText = editText
myEditText.addTextChangedListener(object: TextWatcher {
override fun afterTextChanged(s: Editable?) {
if(myEditText.text.toString() == "" || myEditText.text.toString() == "." || myEditText.text.toString() == "0") {
//setError
myEditText.setError(message)
//var to disable Button
blockcalcbutton = 1
} else {
//delete setError
myEditText.setError(null)
//var to enable Button
blockcalcbutton = 0
}
}
You can create a callback to notify when you set an error or delete it.
interface EditTextErrorListener {
fun onErrorSet()
fun onErrorDeleted()
}
Here you can notify:
if(myEditText.text.toString() == "" || myEditText.text.toString() == "." || myEditText.text.toString() == "0") {
//setError
myEditText.setError(message)
---> listener.onErrorSet()
//var to disable Button
blockcalcbutton = 1
} else {
//delete setError
myEditText.setError(null)
---> listener.onErrorDeleted()
//var to enable Button
blockcalcbutton = 0
}
Try approaching the problem from further away; when you look at this issue, you have multiple inputs (all the fields in your form) and one boolean output:
All fields are OK -> Enable the button
One or more fields are NOT Ok -> disable the button.
Additionally, you have local validation on each field (to display the error, etc.).
I'd argue that the local validation on each field, is to be done at the callback from the edit text (onAfterText, etc.etc.). You are already doing this.
A way to ensure the final validation (of the form as a whole) is fast, you could use a reference counter. E.g.:
Each edit text, validates with afterTextChanged. Each one performs whatever validation you think is right (can be a shared one if they are all the same).
If validation fails, you keep a reference to the failed field.
This will not have side-effects because nothing happens whether the item is or is not on the list.
This is some pseudo-code:
// keep a list of fields (this is just a way to do it, there are many others)
var errorFields = MutableHashSet<EditText>
later in your "validation" (afterTextChanges for example):
if (xxx && yyy && zzz) { //your validations for the individual editText
//setError
myEditText.setError(message)
// Store the reference of the editField in error.
errorFields.add(theEditTextThatHasAFailure).
} else {
myEditText.setError(null)
// If the validation is ok, you remove it:
errorFields.remove(theEditTextThatHasFailure)
}
// The form may have changed, update the global button state.
updateButtonState();
All this method needs to do, is something like:
button.enabled = errorFields.isEmpty()
This will only be empty if there are no error fields.
This is just an idea you may need to combine with callbacks for further control, but remember this one thing:
EditTexts (or any other widget) is and should not be responsible for the business logic that drives the whole "Form"; they are merely individual pieces of a larger puzzle, and as such, it's incorrect to give them the responsibility to drive your Form's validations; they can (and should) however, validate themselves and handle their own error state (like you're doing), but that's as far as it should go.
They can inform of a state change (e.g. via the listener onAfterText, or after gaining/losing focus, etc.) but shouldn't make business logic decisions. EditTexts are designed to take user input and display it on screen, that's all.
Last but not least, don't forget to remove the references when you destroy your views
onDestroy() {
errorFields.clear()
}
Related
I use AutofillManager https://developer.android.com/reference/android/view/autofill/AutofillManager and can't understand how can I detect is user enter value himself or user select any autofill option.
I try to use editText.autofillValue but it contains value both cases
Anyone knows how can I resolve it? Help me, please!)
P.S. code
I have function to request autofill
fun allowAutoFill(view: View?) {
if (view != null) {
val afm = requireContext().getSystemService(AutofillManager::class.java)
if (afm.isAutofillSupported && afm.isEnabled) {
afm?.requestAutofill(view)
}
}
}
After that i want to know user enter something or select value from autofill. It's needed for analytics.
private fun isAutoFillApplied() = binding?.editPassword?.autofillValue?.textValue?.isNotEmpty() == true
but binding?.editPassword?.autofillValue contains value if user enter something and if user select autofill option
I couldn't find cool answer, so I used bad dirty hack.
I have two edittext in screen. If user select any autofill option this edittexts filled the same time. So if time difference on text changed not so big, I fill isAutofill value as true.
This is really not pretty solution, but I can't find another.
This is looks like this
var lastChangedTime = 0L
var isAutoFill = false
var lastRepeatPassword: String? = null
editPassword.addTextChangedListener { text ->
lastChangedTime = System.currentTimeMillis()
}
editRepeatPassword.addTextChangedListener { text ->
if (text.toString() != lastRepeatPassword) {
lastRepeatPassword = text.toString()
isAutoFill = (System.currentTimeMillis() - lastChangedTime) < 50
}
}
I have a test case where in the app "Set as default" prompt is opened. I want to test that with UI automator, and I had success with testing that case, but not 100% reliable. Unfortunately, some devices have "Set as default" prompt button written in caps, and some of those don't, so I'm not able to create 100% reliable tests for this test case. I have written this code below, but when fetching "Set as default" button by text, case of the letters don't play a role, but when I want to interact with that button, text case is important. Switching the IF-ELSE cases doesn't fix the problem in this case. And somehow, none of the dialog buttons ids work (button1, button2..) when I want to press those.
if (roleManager.isRoleAvailable(android.app.role.ASSISTANT)) {
if (!roleManager.isRoleHeld(android.app.role.ASSISTANT)) {
val myApp = device.findObject(UiSelector().textMatches(InstrumentationRegistry.getInstrumentation().targetContext.getString(R.string.app_name)))
myApp.click()
sleepLong()
var setAsDefaultButton: UiObject? = null
if (device.findObject(UiSelector().text("Set as default")) != null) {
setAsDefaultButton = device.findObject(UiSelector().text("Set as default"))
setAsDefaultButton?.click()
} else if (device.findObject(UiSelector().text("SET AS DEFAULT")) != null) {
setAsDefaultButton = device.findObject(UiSelector().text("SET AS DEFAULT"))
setAsDefaultButton?.click()
} else {
clickDialogPositiveButton()
}
}
}
You can use the Pattern object instead of using a string.
You can use in your code like:
val pattern = Pattern.compile("Set as default", Pattern.CASE_INSENSITIVE)
val setDefaultText = device.findObject(UiSelector().text(pattern))
if(setDefaultText != null)) {
setDefaultText.click()
} else {
clickDialogPositiveButton()
}
Based on the Jordan's example and hint, solution to this is to find an object with the Pattern. With pattern, you can search for UIObject with By.text(pattern). Take a note that the object found with the pattern needs to be UIObject2 instead of the UIObject.
val pattern = Pattern.compile("Set as the default", Pattern.CASE_INSENSITIVE)
if(device.findObject(UiSelector().text(pattern.toString())) != null) {
device.findObject(By.text(pattern)).click()
}
Here the Text Area is constantly changing in terms of number and I want to trigger an event when the Text Area gets a particular number example I have tried this -
public void myfunction45(Canvas Panel)
{
if (Indicator = 45) {
Panel.enabled = false;.
}
} //(indicator- www.progress).
But it does not work(it does not read it nothing happens). how do I match the condition as the number is to be specific. please give an example for explanation. Thanks in advance.
That if statement would cause you problems.
You would want:
if(Indicator == 5)
instead. At the moment you're assigning the value without checking it, this would cause a compiler error. If it's just a typo, then update your answer, slightly confusing otherwise.
With regards to checking the text value. You'd have to grab the text value, for that you need a reference to the Text area. This approach assumes that the text area has it's value set by a user. Currently you're not grabbing any text values to compare, as a result, the if statement won't know what to compare.
Here's one approach:
public void myfunction5(Canvas Panel)
{
float result;
string textValue = yourTextArea.text;
if(Single.TryParse(textValue, out result))
{
if(result == Indicator)
{
Panel.enabled = false;
}
}
}
You use TryParse to avoid any potential exceptions that would be thrown if the user entered something that wasn't a number. This method will take the value from your text area, how you get your text area is up to you, and try to parse the text value into a float. The method will return true if the parse was a success, false otherwise.
Here's the reference for the TryParse stuff:
https://msdn.microsoft.com/en-us/library/26sxas5t(v=vs.110).aspx
If you wanted to parse it to an int, then you'd be using the Int32's version of TryParse, https://msdn.microsoft.com/en-us/library/system.int32_methods(v=vs.110).aspx
I'd also recommend having a peak at the Input Field documentation: https://docs.unity3d.com/Manual/script-InputField.html
You can subscribe your method to the Input-fields On Value Changed event, your function will need to tweaked slightly though:
public void myfunction5(string text)
{
float result;
if(Single.TryParse(text, out result))
{
if(result == Indicator)
{
CachedPanel.enabled = false;
}
}
}
Don't forget to store a reference to the panel you want to disable.
Hopefully this is what you're after.
Panel is already a Canvas type, it doesn't make any sense to GetComponent<Canvas> on the same type.
Try using Panel.enabled = false;.
For the rest, we don't know how you get the Indicator reference, or how you built the UI hierarchy, so we can't assess if the problem is there.
Edit: I could I miss the single = baffles me lol. I should avoid answering questions when I'm tired.
When alert/confirm box is popped up on screen and I press device's back button, then the poped up alert/confirm box is getting close(without firing any event). How can I avoid this?
Below is the calling code:
**var buttons = [
{
text : Messages.LBL_OK,
handler : doLogout
}
];
showSuccess(Messages.ALERT_FILING_CONFIRMATION,buttons);**
function showSuccess(text,buttons){
showDialog(Messages.LBL_CMN_DOALOG_SUCCESS_TITLE, text, buttons);
}
function showDialog(title,text,buttons){
if(title == null || title == undefined){
title = Messages.LBL_CMN_DOALOG_TITLE;
}
if(buttons == null || buttons == undefined){
buttons = [
{
text : Messages.LBL_OK,
handler : defaultOK
}
];
}
WL.SimpleDialog.show(title,text,buttons);
}
This is the expected behavior in Android.
However, if you'd like to avoid this default behavior, you could use the WL.App.overrideBackButton API in key locations in your code so that the button will 'do nothing'. When you're done, you can then use WL.App.resetBackButton to reset the back button's behavior back to its default state.
For example:
WL.App.overrideBackButton(callback);
function callback(){
// doing nothing...
}
You could use the above before calling WL.SimpleDialog.show() and dismiss it in the dialog's button callback.
i need a favor.. i'm confused to put these codes to check whether the edittext is empty or not:
String input = editText.getText().toString();
if(input == null || input.trim().equals("")){
Toast.makeText(context, "Sorry you did't type anything"), Toast.LENGTH_SHORT).show();
}
where must i write these codes? is it between these codes?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menuawal);
...
...
...
JmlAhliWarisAnakLK = (EditText) findViewById(R.id.JmlAhliWarisAnakLK);
JmlAhliWarisAnakPR = (EditText)findViewById(R.id.JmlAhliWarisAnakPR);
or in this function after double sisa=0;??
public void cc() {
int JmlWarisAnakPR = Integer.parseInt(JmlAhliWarisAnakPR.getText().toString());
int JmlWarisAnakLK = Integer.parseInt(JmlAhliWarisAnakLK.getText().toString());
int JmlHarta = Integer.parseInt(JmlHartaPeninggalan.getText().toString());
double HasilSuami = 0;
double HasilIstri = 0;
double HasilAnakLK = 0;
double HasilAnakPR = 0;
double sisa = 0;
}
please correct me if i'm wrong.. :D
you are on the right track
After you set the layout using setContentView you need to add your EditText's which you are doing fine as follows.
JmlAhliWarisAnakLK = (EditText)findViewById(R.id.JmlAhliWarisAnakLK);
JmlAhliWarisAnakPR = (EditText)findViewById(R.id.JmlAhliWarisAnakPR);
You then need to store the value you get from the EditText's in some variable,
int JmlWarisAnakPR = Integer.parseInt(JmlAhliWarisAnakPR.getText().toString());
....
....
After you have stored your values you can then call some method that validates your input on click of a button(if you have):
public void validateinput()
{
if(input == null || input.trim().equals(""))
{
Toast.makeText(context, "Sorry you did't type anything"), Toast.LENGTH_SHORT).show();
}
}
According to me, you should put the check on some event, like if its login screen, then on click of submit button. or other wise on focus change it main instantly provide user with the toast that he left the field empty. or if other case, please provide more information for your query. thanks.
That depends on when you want to validate the editText..You propably have some button which "submits" the EditText so call this code in after onClick event gets fired on the button..
Put the input validation code when you have to navigate away from the current activity, either to go to another activity or to save the input details. That's the least annoying place to shove an error message onto the user.
Another approach is to validate when the focus leaves the EditText. But in this case the error notification should be more subtle (and therefore less annoying) like changing the EditText's background to lightred.
Ur questions does not seem to be clear. Are u asking where do u need to put the validation for empty edittext? If this is ur question then the general case would be to validate during any events such as BUTTON CLICK. Set the onClickListener for ur button and inside ur onclick perform the validation.
String input = editText.getText().toString();
if(input == null || input.trim().equals("")){
Toast.makeText(context, "Sorry you did't type anything"), Toast.LENGTH_SHORT).show();
}
Your above code is pretty much correct. You Must need to add above code whenever you want to take input from these edittext, Or whenever you want to save these value. make a function which will return true if edit text is empty so u can ask user to enter values
public boolean isETEmpty(){
String input = editText.getText().toString();
if(input == null || input.trim().equals("")){
Toast.makeText(context, "Sorry you did't type anything"), Toast.LENGTH_SHORT).show();
return true;
}
return false; // if not empty
}
call this function Whenever u want to use values from ET, if this function return true, you must let user enter values. Such as on Button Click to save etc