Unable to get id from TableView in Appcelerator - titanium

I attached some eventListeners to a number of elements, like this:
$.someButton.addEventListener('click', function(evt) { eventHandling(evt); });
$.someImageView.addEventListener('click', function(evt) { eventHandling(evt); });
$.someWindow.addEventListener('click', function(evt) { eventHandling(evt); });
$.someTableView.addEventListener('click', function(evt) { eventHandling(evt); });
Then, I catch them like this:
function eventHandling(evt) {
switch (evt.source.id) {
case "someButton":
console.log("button clicked");
break;
case "someImageView":
console.log("imageview clicked");
break;
case "someWindow":
console.log("window clicked");
break;
case "someTableView":
console.log("tableview clicked");
break;
};
};
They all log their id's, except the TableView which logs undefined.
The TableView is set like this (minimised):
<Alloy>
<View id="main">
<TableView bottom="100" zIndex="0" id="someTableView" dataCollection="inspection" dataFilter="statusFilter">
...
</TableView>
</View>
</Alloy>
Why isn't this working?

To tell you more clearly on why this error is happening, we need more UI/XML code to know how TableView is linked with other UI elements.
The only guess right now is that any of the TableView Row's child element(s) can also fire that click event. Can you also share the code where you are getting undefined printed on console ?
Apart from this, I observe a less useful code pattern here - Why are you using switch statement just to know the id of clicked element?
I would prefer to use below code instead of above code.
$.someButton.addEventListener('click', buttonClick);
$.someImageView.addEventListener('click', imageViewClick);
$.someWindow.addEventListener('click', windowClick);
$.someTableView.addEventListener('click', tableClick);
function buttonClick(e) {
// .....
}
function windowClick(e) {
// .....
}
function imageViewClick(e) {
// .....
}
function tableClick(e) {
// .....
}
The point here is that running the code by assuming the id of source-view which fired that event is not a good-idea, because your layout might change in future or you can rename the IDs of those elements or could be any other reason.

Related

vue-bootstrap alert showing only once

https://bootstrap-vue.js.org/docs/components/alert/
I am trying to show an alert on a button click for a second and hide it away, then show it again when button is clicked again,
<b-alert :show="saved" >Default Alert</b-alert>
..
clicked() {
//1 sec delay
this.saved = 1
}
I was hoping this would show the alert and reset the "saved" to 0 or something so when I click the button it would show again, I even tried to set the value to 0 after the click but no avail.
In their other examples they have done similar things with additional methods like 'countDownChanged','showAlert', I just want to know if that can be done without that.
Any help is appreciated.
Please refer the following code. Its working fine for me.
<button #click="test">lalala</button>
<b-alert :show="showvar" >Default Alert</b-alert>
data: {
showvar:false,
sec:1000
},
methods: {
test: function() {
console.log("hi")
let self = this;
self.showvar=true
setTimeout(function(){ self.showvar=false; }, self.sec);
}
}
codepen - https://codepen.io/anon/pen/QoeNro

Vue Draggable with touch - drop doesn't trigger

I have been working on a website that has to function on both desktop and tablets. Part of the website is having three columns and being able to drag orders from column to column. Sometimes on drop, the user has to answer a few questions or change some of the data of that specific order. This happens in a pop-up window that is triggered by an #drop function (for example #drop="approved()". The method approved() then checks the status of the dropped order and shows the pop-up window).
When I am on desktop, everything works just fine. But when I switch to iPad Pro in the developer tools, nothing happens. I implemented Vue Draggable, which says to work with touch devices. In their examples I can't find anything about touch events or adding new handles for touch, so I don't know what to do now.
The dragging works just fine with touch devices, it's just the #drop function that doesn't trigger.
The dropzone (it includes a component that contains the draggables and a lot of if-statements):
<div class="col-md-4 border" #dragover.prevent #drop="approved()">
<Wachtrij class="fullHeight" :data2="opdrachtenData2"></Wachtrij>
</div>
The method:
export default {
methods: {
...
approved() {
console.log("Function approved() is being executed.")
if (this.draggingOrder.status === 5) {
this.popupGekeurd = true;
}
else if (this.draggingOrder.status === 6) {
this.popupTochGoed = true;
}
else if ([40, 52, 42,41,49,55,54].indexOf(this.draggingOrder.status) !== -1) {
this.back = true;
}
},
...
}
}
The problem seems to be that you are using native events, while the touch implementation does not (always?) use these events. It is intended that you use a draggable component with one of the events outlined in the documentation. In your case the start and end events look promising. This event has a few properties (docs), some of them being to and from.
Let's assume that we have the following code:
<draggable v-for="(zone, index) in zones" v-model="zones[index]" :class="['dropzone', `zone-${index}`]" :key="`dropzone-${index}`" :options="options" #start="start" #end="end">
<div v-for="item in zones[index]" class="dropitem" :key="`dropitem-${item.id}`">
{{ item.title }}
</div>
</draggable>
This creates a few zones, each filled with their own items. Each array item of zones is changed based on where you move each item. You can then use start to have information on when you start moving an item, and end to have information on when you stop moving an item, and where that item came from and where it ended up. The following methods show off what you can do with that in this case:
methods: {
start (event) {
console.log('start', event);
},
end (event) {
console.log('end', event);
const { from, to } = event;
if (to.className.match(/\bzone-2\b/)) {
console.log('Zone 2 has something added!')
}
if (from.className.match(/\bzone-0\b/)) {
console.log('Zone 0 had something removed!');
}
}
}
We make our dropzones with a class zone-0, zone-1 or zone-2 in this case, so we can use the class name to determine which dropzone we ended up in.
An alternative way to determine which zone was changed is to simply use a watcher. Since zones changes based on where you move items, you can simply watch a particular dropzone for changes and do things based on that.
watch: {
'zones.1': {
handler (oldZone, newZone) {
if (Array.isArray(oldZone) && Array.isArray(newZone) && oldZone.length !== newZone.length) {
console.log('Zone 1 was changed from', oldZone, 'to', newZone);
}
}
}
}
A full example can be found on codesandbox.

FLEX Button event handling

I have a scenario where i have 5 buttons which call the same method when clicked. These buttons are clicked in various conditions, but now i want to know how we determine that which particular button has been clicked, from the called method.
For example, i have been calling chocolate() method when i click the buttons, eclairs, dailrymilk, cadbury, snickers and kitkat. Now i will click anyof these buttons from the UI and i want to know which one is clicked. this event has to be handled in the chocolate() method only.
Please suggest me how can i implement this. I am using Adobe Flex 3
If you are not using the addEventListeners but are setting the click property in your buttons you could do something like that:
<s:Button id="snickers"
click="{chocolate('snickers')}"
label="snickers"/>
<s:Button id="kitkat"
click="{chocolate('kitkat')}"
label="kitkat"/>
private function chocolate(type:String):void
{
trace("button", type, "was clicked");
if(type == "snickers")
{
// do stuff
}
else if(type == "kitkat")
{
// do something else
}
}
if you are working with event listeners you could determine the buttons from their ids, for example:
<s:Button id="snickers"
label="snickers"/>
<s:Button id="kitkat"
label="kitkat"/>
// add your event listeners somewhere like in onCreationComplete
snickers.addEventListener(MouseEvent.CLICK, chocolate);
kitkat.addEventListener(MouseEvent.CLICK, chocolate);
private function chocolate(e:MouseEvent):void
{
// e.target is the component that has dispatched the event (a button in this case)
var type:String = e.target.id;
trace("button", type, "was clicked");
if(type == "snickers")
{
// do stuff
}
else if(type == "kitkat")
{
// do something else
}
}

WinJS Listview shows undefined when navigating quickly

I have a WinJS application with listviews in which if quickly navigate between pages before the listview is fully loaded, the next page shows the listview with all elements in it bound as "undefined".
So say I have a hub page with a "to do" that is filtered to only show 6 items, and there is a header that navigates to the full "to do" page, when the hub page is displayed but before it is fully loaded I click on the header link to the "to do" page, the app then goes to the "to do" page, but the items show up with all the properties in the tile as "undefined".
I am using IndexedDB as my data store.
My home page code looks like this:
WinJS.UI.Pages.define("/pages/home/home.html", {
ready: function (element, options) {
WinJS.Utilities.query("a").listen("click", function (e) {
e.preventDefault();
WinJS.Navigation.navigate(e.currentTarget.href);
}, false);
viewModel = new HomeViewModel(element);
viewModel.load(); //loads from indexed db
},
//etc...
To Do Page:
WinJS.UI.Pages.define("/pages/ToDo/ToDo.html", {
ready: function (element, options) {
viewModel = new ToDoViewModel(element);
viewModel.load();
},
etc//
I know there isn't much to go off, but any ideas would be appreciated.
Also tips on how to debug something like this would be great.
Update
I narrowed it down to this one line from the Hub Page:
myLib.GetData(todaysDate, function (result) {
that.trendsModel.today = result;
WinJS.Binding.processAll(that.el.querySelector("#dataPanel"), that.trendsModel); //<--Right Here
});
If I remove that, then when I load the second page the data doesn't show as undefined. What is interesting is the data initially shows correctly on the second page and then it changes to "undefined".
Solution
My fix:
myLib.GetData(todaysDate, function (result) {
var element = that.el.querySelector("#dataPanel");
that.trendsModel.today = result;
if(element) {
WinJS.Binding.processAll(element, that.trendsModel);
}
});
At the point when when the callback returns, I am already on the second page. So the selector was not found returning null. If you pass null to processAll it tries to bind the whole page which is why I was able to see the correct data for a second then it changes to undefined...Wow, what a doozy. I guess it makes sense but what a pain to find.
Hope it helps someone in the future :)
Your ToDoViewModel, and HomeViewModel need to be observable. This means they need to mix in from WinJS.Binding.mixin, and for the properties that you pull in asynchronously, they need to call this.notify("propertyName", newVal, oldVal) from the property setter.
Note that you need to have getter/setter properties. e.g.
var bindingBase = WinJS.Class.mix(function() {}, WinJS.Binding.mixin);
WinJS.Namespace.define("YourNamespace", {
ToDoViewModel: WinJS.Class.derive(bindingBase, function constructor() {
}, {
_titleStorage: "",
title: {
get: function() { return this._titleStorage; },
set: function(newValue) {
if(newValue === this._titleStorage) {
return;
}
var old = this._titleStorage;
this._titleStorage = newValue;
this.notify("title", newValue, old);
}
}
}),
});
myLib.GetData(todaysDate, function (result) {
var element = that.el.querySelector("#dataPanel");
that.trendsModel.today = result;
if(element) {
WinJS.Binding.processAll(element, that.trendsModel);
}
});
At the point when when the callback returns, I am already on the second page. So the selector was not found returning null. If you pass null to processAll it tries to bind the whole page which is why I was able to see the correct data for a second then it change to undefined...Wow, what doozy. I guess it makes sense but what a pain to find.

create a window chrome with an exception in back

I'd just like to create a new window from the background page and put it in back. I tried focused:false but it doesn't seem to make the trick. I tried to save the previous windowId and tabId and update it after having creating the new window but it doesn't solve the problem neither.
Do you know how we can do that?
Here is my code:
function saveTabId() {
// Get the current tab
chrome.tabs.getSelected(null,function(tab){
if (tab != 'undefined') {
if (tab.windowId != windowId) {
currentTabId = tab.id;
currentWindowId = tab.windowId;
}
chrome.windows.create({url:"http://www.google.com", width:100, height:100, top:0, left:0, focused:false}, function() {
chrome.tabs.get(currentTabId, function(tab) {
chrome.windows.update(tab.windowId, {}, function(w) {
chrome.tabs.update(tab.id, {selected:true});
});
});
});
}
});
}
I launched this code at the beginning of background.html and when I refresh the extension, the window is on top of the extensions tab.
P.S: something more strange the window is on top of the extensions tab and when I change tab in this window, the new window stays on top of the other one even if I click and type text in the other one...
I got it kind of working, but popup window is still showing up for a moment before going underneath the current window:
chrome.windows.create({url:"http://www.google.com", width:100, height:100, top:0, left:0, focused:false}, function() {
chrome.windows.update(currentWindowId, {focused:true});
});
Thanks, here is the code I'm using now. The problem in the code of the question was the focus to the other window before updating it. It is strange, when you focus on a window, it doesn't show it on top of the others.
function focusTab(tabId) {
chrome.tabs.get(tabId, function(tab) {
chrome.windows.update(tab.windowId, {}, function(w) {
chrome.tabs.update(tab.id, {selected:true});
});
});
}