Currently in my Web app I'm doing As shown in the below Code.
So What happens after reaching the $window.Confirm compiler waits for response on Alert box and depending on that Leave gets true or false.
Finally this method returns that boolean value to its coupled method.
//** IN WEB APP**//
function shouldLeave(next)
var message = 'Do you wish to leave this Page';
var leave = $window.confirm(message); // Return bool value as per user selection
if (leave) {
//Doing my job...
reset();
}
return leave;
}
Now for Hybrid What I'm doing is:
function shouldLeave(next) {
var message = 'Do you wish to leave this Page';
var leave = notification.confirm(message, callbackMethod(),title,[Ok, Cancel]); // Here there is no return value . Return depends on Callback as the callback method gets called depending on user selection
if (leave) {
//Doing my job...
reset();
}
return leave;
}
function CallBack(index)
{
switch(index)
{
case 1 :
leave=true; break;
case 2 :
leave=false; break;
default:
leave=-1; break
}
return leave;
}
So here after executing the Notification.confirm compiler is not waiting for user response and moving to Next line.(but for Window. Confirm is was doing so).
So Now my doubt is how to refactor this code so that mu Should leave method will return the proper leave value to its coupled method. Because by the time my callback method executes after user interaction in hybrid app shouldLeave completes its execution. So its not behaving like $window.confirm functionality.
Any suggestion is appreciated.
Check this
function shouldLeave() {
var message = 'Do you wish to leave this Page';
navigator.notification.confirm(
message, // message
onConfirm, // callback to invoke with index of button
'Confirmation', // title
'Ok, Cancel' // buttonLabels
);
}
//on button press, the onConfirm function is called
function onConfirm(button) {
//console.log('You selected button ' + button);
if(button == 1){
//pressed "Ok"
console.log("Ok ACTION");
}
else if(button == 2){
//pressed "Cancel"
console.log("Cancel ACTION");
}
}
This should work.
change
notification.confirm(message, callbackMethod(), title, [Ok, Cancel]);
to
notification.confirm(message, callbackMethod, title, [Ok, Cancel]);
Explanation:
if you put callbackMethod(), it is executed as soon as the execution reach that line
if you put callbackMethod withouth the (), you are declaring the function to be executed on the callback.
Related
I would like to count the attempts entering the PIN and show notifications accordingly:
val remainingPinCounter = remember { mutableStateOf(3) }
//
if(pinState == WRONG_PIN) {
remainingPinCounter.value--
showWrongPinNotification(remainingPinCounter)
}
#Composable
private fun showWrongPinNotification(retries: MutableStateOf<Int>){
if(retries.value > 0) Log.d("TAG", "Remaining Retries := $retries.value)
else Log.d("TAG", "All $retries.value attempts failed!)
//..
}
But the showWrongPinNotification() is called continously with increasing remainingPinCounter to -infinity , although I decrement it via pinState == WRONG_PIN only?! I guess the state WRONG_PIN is not changing and thus constantly calling showWrongPinNotification with decremented values?
It worked properly without remeber ->val remainingPinCounter = 3
if(pinState == WRONG_PIN) {
remainingPinCounter.value--
showWrongPinNotification(remainingPinCounter)
}
might be the infinite recompositions if you don't change pinState before next recomposition. If that's the case on each recomposition conditional block is invoked and value of remainingPinCounter changed constantly.
LaunchedEffect(pinState) {
if(pinState == WRONG_PIN) {
remainingPinCounter.value--
showWrongPinNotification(remainingPinCounter)
}
}
Other option is to decrease it only once using LaunchedEffect as
The below code is for Jetbrains Desktop Compose. It shows a card with a button on it, right now if you click the card "clicked card" will be echoed to console. If you click the button it will echo "Clicked button"
However, I'm looking for a way for the card to detect the click on the button. I'd like to do this without changing the button so the button doesn't need to know about the card it's on. I wish to do this so the card knows something on it's surface is handled and for example show a differently colored border..
The desired result is that when you click on the button the log will echo both the "Card clicked" and "Button clicked" lines. I understand why mouseClickable isn't called, button declares the click handled. So I'm expecting that I'd need to use another mouse method than mouseClickable. But I can't for the life of me figure out what I should be using.
#OptIn(ExperimentalComposeUiApi::class, androidx.compose.foundation.ExperimentalDesktopApi::class)
#Composable
fun example() {
Card(
modifier = Modifier
.width(150.dp).height(64.dp)
.mouseClickable { println("Clicked card") }
) {
Column {
Button({ println("Clicked button")}) { Text("Click me") }
}
}
}
When button finds tap event, it marks it as consumed, which prevents other views from receiving it. This is done with consumeDownChange(), you can see detectTapAndPress method where this is done with Button here
To override the default behaviour, you had to reimplement some of gesture tracking. List of changes comparing to system detectTapAndPress:
I use awaitFirstDown(requireUnconsumed = false) instead of default requireUnconsumed = true to make sure we get even a consumed even
I use my own waitForUpOrCancellationInitial instead of waitForUpOrCancellation: here I use awaitPointerEvent(PointerEventPass.Initial) instead of awaitPointerEvent(PointerEventPass.Main), in order to get the event even if an other view will get it.
Remove up.consumeDownChange() to allow the button to process the touch.
Final code:
suspend fun PointerInputScope.detectTapAndPressUnconsumed(
onPress: suspend PressGestureScope.(Offset) -> Unit = NoPressGesture,
onTap: ((Offset) -> Unit)? = null
) {
val pressScope = PressGestureScopeImpl(this)
forEachGesture {
coroutineScope {
pressScope.reset()
awaitPointerEventScope {
val down = awaitFirstDown(requireUnconsumed = false).also { it.consumeDownChange() }
if (onPress !== NoPressGesture) {
launch { pressScope.onPress(down.position) }
}
val up = waitForUpOrCancellationInitial()
if (up == null) {
pressScope.cancel() // tap-up was canceled
} else {
pressScope.release()
onTap?.invoke(up.position)
}
}
}
}
}
suspend fun AwaitPointerEventScope.waitForUpOrCancellationInitial(): PointerInputChange? {
while (true) {
val event = awaitPointerEvent(PointerEventPass.Initial)
if (event.changes.fastAll { it.changedToUp() }) {
// All pointers are up
return event.changes[0]
}
if (event.changes.fastAny { it.consumed.downChange || it.isOutOfBounds(size) }) {
return null // Canceled
}
// Check for cancel by position consumption. We can look on the Final pass of the
// existing pointer event because it comes after the Main pass we checked above.
val consumeCheck = awaitPointerEvent(PointerEventPass.Final)
if (consumeCheck.changes.fastAny { it.positionChangeConsumed() }) {
return null
}
}
}
P.S. you need to add implementation("androidx.compose.ui:ui-util:$compose_version") for Android Compose or implementation(compose("org.jetbrains.compose.ui:ui-util")) for Desktop Compose into your build.gradle.kts to use fastAll/fastAny.
Usage:
Card(
modifier = Modifier
.width(150.dp).height(64.dp)
.clickable { }
.pointerInput(Unit) {
detectTapAndPressUnconsumed(onTap = {
println("tap")
})
}
) {
Column {
Button({ println("Clicked button") }) { Text("Click me") }
}
}
Trying to use data outside of the submit function to use my own validation
onBlur = {
() = > {
setNameError(nameValidation(data.name));
}
}
You should not handle validation with onBlur function first of all. You can listen to events on form using these approaches so that you capture both form input and button click.
I have not covered styling of form . You can look into more info link to do that one but yeah, just add or remove a class as shown in code below which either shows validation text or not show based on input changes.
// create form with id/class
// There are many ways to pick a DOM node; here we get the form itself and the email
// input box, as well as the span element into which we will place the error message.
const form = document.getElementsByTagName('form')[0];
const email = document.getElementById('mail');
const emailError = document.querySelector('#mail + span.error');
// add an event listener to listen to both form and button click which are defined by id "email" and "submit" as button events.
email.addEventListener('input', function(event) {
// Each time the user types something, we check if the
// form fields are valid.
if (email.validity.valid) {
// In case there is an error message visible, if the field
// is valid, we remove the error message.
emailError.textContent = ''; // Reset the content of the message
emailError.className = 'error'; // Reset the visual state of the message
} else {
// If there is still an error, show the correct error
showError();
}
});
form.addEventListener('submit', function(event) {
// if the email field is valid, we let the form submit
if (!email.validity.valid) {
// If it isn't, we display an appropriate error message
showError();
// Then we prevent the form from being sent by canceling the event
event.preventDefault();
}
});
// finally kick off the error that validates input or button click both and displays error if needed.
function showError() {
if (email.validity.valueMissing) {
// If the field is empty,
// display the following error message.
emailError.textContent = 'You need to enter an e-mail address.';
} else if (email.validity.typeMismatch) {
// If the field doesn't contain an email address,
// display the following error message.
emailError.textContent = 'Entered value needs to be an e-mail address.';
} else if (email.validity.tooShort) {
// If the data is too short,
// display the following error message.
emailError.textContent = `Email should be at least ${ email.minLength } characters; you entered ${ email.value.length }.`;
}
// Set the styling appropriately
emailError.className = 'error active';
}
More info
// On react way
handleOnChange(ev): React.MouseEvent {
this.validateUserInput(ev):
}
const validateUserInput = (ev) => {
if (ev.target.textContent.indexOf(Regular expression logic goes here)) {
this.state.setState({
formValidationText: "Character must be 3 at least"
})
}
}
const renderValidationText = () => { <
h1 > {
this.state.formValidationText
} < /h1>
}
render() {
return <>
<input placeholder="Enter your name" onChange = {
(ev) => this.handleOnChange.bind(this)
}/>
{this.renderValidatorText}
/>
}
I am creating an inkcanvas (CustomInkCanvas) that receives Gestures. At different times during its use, I am placing additional panels over different parts of the inkcanvas. All is well, and the part of the CustomInkCanvas that is not covered by another panel responds appropriately to ink and gestures.
However, occasionally a Gesture is not recognized, so in the default code of the gesture handler, I am trying to remove the ink from the CustomInkCanvas--even when it is not the uppermost panel.
How is this done?
Note: I have tried everything I can think of, including:
Dispatcher with Background update as:
cink.InkPresenter.Dispatcher.Invoke(DispatcherPriority.Background, EmptyDelegate);
Clearing the strokes with:
Strokes.Clear();
cink.InkPresenter.Strokes.Clear();
Invalidating the visual with:
cink.InkPresenter.InvalidateVisual();
cink.InavlidateVisual();
And even
foreach (Stroke s in Strokes)
{
cink.InkPresenter.Strokes.Remove(s);
}
Here is the full code...
void inkCanvas_Gesture(object sender, InkCanvasGestureEventArgs e)
{
CustomInkCanvas cink = sender as CustomInkCanvas;
ReadOnlyCollection<GestureRecognitionResult> gestureResults = e.GetGestureRecognitionResults();
StylusPointCollection styluspoints = e.Strokes[0].StylusPoints;
TextBlock tb; // instance of the textBlock being used by the InkCanvas.
Point editpoint; // user point to use for the start of editing.
TextPointer at; // textpointer that corresponds to the lowestpoint of the gesture.
Run parentrun; // the selected run containing the lowest point.
// return if there is no textBlock.
tb = GetVisualChild<TextBlock>(cink);
if (tb == null) return;
// Check the first recognition result for a gesture.
isWriting = false;
if (gestureResults[0].RecognitionConfidence == RecognitionConfidence.Strong)
{
switch (gestureResults[0].ApplicationGesture)
{
#region [Writing]
default:
bool AllowInking;
editpoint = GetEditorPoint(styluspoints, EditorPoints.Writing);
at = tb.GetPositionFromPoint(editpoint, true);
parentrun = tb.InputHitTest(editpoint) as Run;
if (parentrun == null)
{
AllowInking = true;
TextPointer At = tb.ContentEnd;
Here = (Run)At.GetAdjacentElement(LogicalDirection.Backward);
}
else
{
Here = parentrun;
AllowInking = String.IsNullOrWhiteSpace(parentrun.Text);
}
*** THIS FAILS TO REMOVE THE INK FROM THE DISPLAY ???? *********
if (AllowInking == false)
{
foreach (Stroke s in Strokes)
{
cink.InkPresenter.Strokes.Remove(s);
}
// remove ink from display
// Strokes.Clear();
// cink.InkPresenter.Strokes.Clear();
cink.InkPresenter.InvalidateVisual();
cink.InkPresenter.Dispatcher.Invoke(DispatcherPriority.Background, EmptyDelegate);
return;
}
// stop the InkCanvas from recognizing gestures
EditingMode = InkCanvasEditingMode.Ink;
isWriting = true;
break;
#endregion
}
}
}
private static Action EmptyDelegate = delegate() { };
Thanks in advance for any help.
It would be nice to get a guru response to this, but for anybody else getting here, apparently the strokes that go into creating the gesture have not yet been added to the InkCanvas, so there is nothing to remove or clear from the inkcanvas from within the gesture handler. Strokes are only added to the InkCanvas AFTER the gesture handler. The solution this newbie ended up with was to set a flag when ink was not allowed, and then act on it in the StrokesChanged handler like:
if (AllowInking == false)
{
ClearStrokes = true;
return;
}
void Strokes_StrokesChanged(object sender, StrokeCollectionChangedEventArgs e)
{
if (ClearStrokes == true)
{
ClearStrokes = false;
Strokes.Clear();
return;
}
All works now. Is there a better way?
I'm using jquery UI's tabs. When a user switches tabs, I'm checking for unsaved changes, and prompting the user accordingly. However, before the user even clicks Yes or No, the tab loads anyway. Does anyone know how I can get my function to NOT return anything until after the result has come back from my fancybox dialog?
You can see I've tried a couple of different methods to return my boolean value in CheckSomething().
$("#myTabs").tabs({
select:
function (event, ui) {
return CheckSomething();
},
show:
function (event, ui) {
//do some stuff
}
});
function CheckSomething() {
var loadMyTab = true; //If I set this to false, then it always returns false.
if (myCondition) {
//Show a FancyBox prompt.
if (fancyYes) {
//return true;
loadMyTab= true;
}
else {
//return false;
loadMyTab = false;
}
}
else {
//return true;
loadMyTab = true;
}
return loadMyTab;
}
With a standard confirm instead of a fancy is working can it be a fast solution? http://jsfiddle.net/nuywj/
I ended up going w/ a standard javascript confirm box instead of FancyBox. That solved my problem, because Confirm will block code from being executed:
function CheckSomething() {
if (myCondition) {
return confirm("Are you sure you want to change tabs without saving?");
}
else {
return true;
}
}