Doubletap on textfield - sencha-touch

In my mobile app, I have a FormPanel with a fieldset with textfields that could have been filled from some desktop application, by a skilled secretary with well beyond 300 keystrokes per minute.
So I want to provide the possibility to open a bigger field on doubletap onto the textfield, but I can't get the listener to work.
As of now, my code looks like this:
config:{
...
listeners : [{
fn:'onClearIconTap',
event:'clearicontap',
delegate:'textfield'
},{
fn:'onItemDblTap',//'onTextFieldDblTap',
event:'itemdoubletap',//'doubletap'
//delegate:'fieldset'//'textfield'
}]
The clearIconTap event is fired, but I can't get the doubletap to work.
How can I listen to that event?

That is expected behaviour, if you check Ext.field.Text documentation the doubletap event is not exposed by that component. That is a design choice for performance reason, they chose to listen to and expose only the events they considered relevant for each component.
That said, you can listen to events directly on the Ext.dom.Element associated to that component:
Try this:
{
fn:'onItemDblTap',
event:'doubletap',
element: 'element'
}

Related

v-navigation-drawer drops into a runaway loop on window resize

First, let me say that the v-navigation-drawer works as intended, i.e.:
On clicking the hamburger menu the TOGGLE_DRAWER mutation is committed, and it toggles open/closed, updating the state.
On window resize it opens/closes at a designated breakpoint
So it works.
BUT the window resize does not properly toggle the mutation and I keep getting a Vuex mutation error when I resize the window:
I understand why I'm getting this error - the $store.state.ui.drawer is being modified outside of the mutator (it's the v-navigation-drawer's v-model):
<v-navigation-drawer
v-model="$store.state.ui.drawer"
app
clipped
>
I get it's bad form to bind the state to the v-model. But when I try to make a drawer computed property with a get() and set() method that properly gets/commits a mutation, the browser crashes (presumably because the set method triggers an endless loop of commits toggling drawer true/false into infinity):
computed: {
drawer: {
get () {
return this.$store.state.ui.drawer
},
set () {
this.$store.commit('TOGGLE_DRAWER') // <--crashes the browser
}
}
}
I've searched endlessly for a solution to this problem. It's bugging me even though it visually appears to be working.
I've considered running the v-navigation-drawer in stateless mode and handling all the window resize events and state updates manually. I've also considered disabling 'Strict' mode in Vuex (which would hide the errors). But the former is a lot more complexity and the latter is a bandaid that costs me debugging insight in development.
This sounds like a perfect candidate for Lodash's debounce function. If you need to stick with using setter/getter while applying this effect, have a look at this post; otherwise, this one for sequential event subscription on any of the lifecycle hooks.
After spending some time with this, I think I have a solution. Wanted to share for anyone else that may be facing the same issue with VNavigationDrawer using Vuex state to control visibility.
The #input event passes a val parameter, which includes the state of the drawer after the window resizes. I created a new action that is called by the below function:
<v-navigation-drawer
:value="$store.state.ui.drawer"
app
clipped
#input="updateDrawer($event)"
>
Here is the action being dispatched:
methods: {
updateDrawer(event) {
if (event !== this.drawer) { // avoids dispatching duplicate actions; checks for unique window resize event
this.$store.dispatch('updateDrawer',event)
}
}
},
And the action commits the new val to the Vuex store.
Basically, the input event is able to watch for updates to the drawer, and subsequently update the drawer state if it's necessary.
You'll also see above that I stubbornly accepted using :value as the docs suggest, even though I think this should be controlled by a v-model.
Seems to be working - with the right events called and the state being updated appropriately.

Programatically assign handler for native event in Vue JS?

I am trying to leverage a Vue mixin to add behavior when a native event happens. Using a mixin will allow me to share that across several components. Specifically, when a field component (or button, or checkbox, etc.) has focus, and the Escape key is pressed, the field loses focus.
A similar Stack Overflow question seemed to indicate I could listen for native events (see code comment about multiple events).
However, the Vue Documentation for programmatically adding an event listener using $on says that it will
Listen for a custom event on the current vm...
(Emphasis added)
Unsure if the custom event remark is absolute or based on the context, I have been experimenting. I have been trying to listen for the native keyup event (using the Vue alias keyup.esc) but have had no success. So I am wondering if it is indeed limited to custom events, and if so, why?
You can see my experiment in a code sandbox. The custom event works, the native does not.
The mixin looks like so:
// escape.mixin.js
export default {
created() {
// Custom event
this.$on("custom-event", function() {
console.log("Custom event handled by mixin");
});
// Native event
this.$on(["keyup.esc", "click"], function() {
alert("Native event handled!");
});
}
};
The main point of all this is to be able to add the behavior to a set of components by adding to how the event is handled, without overriding behavior that might also exist on the component. The secondary goal is to provide the behavior by simply adding the mixin, and not having to do component level wiring of events.
So a component script would look something like this:
// VText component
import escapeMixin from "./escape.mixin";
export default {
name: "VText",
mixins: [escapeMixin],
methods: {
onFocus() {
console.log("Has Focus");
this.$emit("custom-event");
}
}
};
Also, I was trying to avoid attaching the listener to the <input> element directly with vanilla JS because the Vue documentation suggested that letting Vue handle this was a good idea:
[When using v-on...] When a ViewModel is destroyed, all event listeners are automatically removed. You don’t need to worry about cleaning it up yourself.
Solution
skirtle's solution in the comment below did the trick. You can see it working in a code sandbox.
Or here's the relevant mixin:
export default {
mounted() {
this.$el.addEventListener("keyup", escapeBlur);
},
beforeDestroy() {
this.$el.removeEventListener("keyup", escapeBlur);
}
};
function escapeBlur(e) {
if (e.keyCode === 27) {
e.target.blur();
console.log("Lost focus");
}
}

Is there a "onExpand" event or similar for dijit.TitlePane?

Is there any way to get an event callback when the dojo-dijit's TitlePane expands?
I can capture onClick on the TitlePane. However, that is not enough for me. I have a button for "Expand All" TitlePanes. When user clicks on that I iterate on all TitlePanes and call it's toggle() method. When that happens, onClick event is not fired (as expected). I was wondering if there is any event fired upon toggle().
Or any other smart ways to address it also will be appreciated.
After looking into documentation in detail, I do not think there is any built in event that is fired during the toggle/expand. I ended up firing a custom event, and that helped me get what I wanted.
This answer helped me - https://stackoverflow.com/a/12852043/3810374
Basically,
First using isOpen() method, ensure the title pane is not already expanded. Then call toggle() method, and fire a custom event like this:
require(["dojo/on"], function(on){
// Send event
on.emit(target, "onExpand", {
bubbles: true,
cancelable: true
});
});
And then handle the event:
require(["dojo/on"], function(on){
// register event handler
on(target, "onExpand", function(e){
// handle event
});
});
You may be wondering, why not just do the work right after toggle(), instead of going through the pain of firing/handling event. I needed to handle the event in a particular closure, where I have access to other objects and variables.

call a function when tapping on mask outside a floating component

I'm working on a Sencha touch app. Inside a listener, I set up a panel with hideOnMaskTap set to true (based on code from the floating components documentation):
onTap: function() {
Ext.Viewport.add({
xtype: 'panel',
modal: true,
hideOnMaskTap: true,
...
}
This works as expected. Apart from hiding the panel, I would like to call a function when the user taps on the mask. After looking at the sencha documentation and having googled many things, I haven't been able to find a way to make such a call.
Any pointers would be greatly appreciated.
When modal:true and hideOnMaskTap:true, once you click on the mask, the component will be hidden. This will fire the hide event.
hide( Ext.Component this, Object eOpts )
Fires whenever the Component is hidden
Write your code in the handler for this event.

ComponentQuery for a parent with ExtJS4?

Is there a way to query "up"? I'm in a Component and want to register listeners to it's parents events with control(). This requires a Query which gets me the parent of my main view.
In ExtJS4, you can use 'up()' from an Ext Element.
The params are a string of the parent element you wish to find e.g:
var parentEl = Ext.get('childID').up('div.parentClass');
If you provide some details about the structure of your components/elements I can give a specific example which should fit.
EDIT: To show going 'up' from a component
var myComponent = // however you've got it
var theParentEl = myComponent.getEl().up('div.parentClass');
Usually up('PARENTCLASS') is enough for what you're trying to do. Here is what I do all over the code so elements generates event for the form they are in:
items: [
...
{ xtype: 'checkbox', listeners: {
change: function() { this.up('window').fireEvent('checkboxchanged'); }
}}
...
]
As I understand, you want to listen to events dispatched by a component's parent from the child component's controller control function specifically.
There is not a query selector like 'parent < component' which you can put in the child controller's control function to listen to parent events.
Normally I would just add the parent view to the child's controller, then you could listen to it's events. But I assume you are not doing this because you are trying to delegate to different controllers or something.
You could fire an event in the child component whenever that parent event occurs. Inside the parent controller you could do it like this:
var child = parent.down('child');
child.fireEvent('myOwnEventName', arg1, arg2, arg3, etc);
Then you would add a handler for 'myOwnEventName' in the child controller's control function to run the logic you wanted for it.
If the parent doesn't have a controller then you should just add the parent component as a view in the child's controller.
The Sencha help says "Member expressions from candidate Components may be tested. If the expression returns a truthy value, the candidate Component will be included in the query:" in the http://docs.sencha.com/ext-js/4-0/#!/api/Ext.ComponentQuery help.
Took me a while to realize I can do the following in my controller:
this.control({
'window{down("testcomp")}[down]': { beforedestroy: this.doNotCloseIfUnsaved }
});
Using the {} operation, we can call any arbitrary code. Really bad from an efficiency standpoint, but it got the job done. I had to add the [down] because it runs component queries from right to left, so we have to be sure down() exists before we try running it (on every component). Thus, I was able to attach an event to whatever window holds my component.
Of course, other functions can be used too, like child() instead of down() if you want to ensure it is the immediate child rather than just anywhere below.