SortableJS not working with Onsen UI on desktop - onsen-ui

Just copy-pasted the example code from Sortable's docs.
It works fine on any touchsreen device, but as soon as I view it on Chrome or any other desktop browser it stops working. No error, you just can't drag anymore.
Onsen UI's JS probably overwrites the drag events or something like that but couldn't manage to find the solution.

Per the answer given here: https://github.com/SortableJS/Vue.Draggable/issues/508#issuecomment-488314106
If anybody faces this issue then the following is a workaround for this;
document.body._gestureDetector.dispose()
If you need to enable it again for any reason, use the following
document.body._gestureDetector = new ons.GestureDetector(document.body);
Since my code is using Sortable in a Vue component, I ended up doing this as part of the options to Sortable.create. It seems to work well enough:
onChoose: function(event) {
if(this.$ons) {
document?.body?._gestureDetector?.dispose();
}
},
onStart: function(event) {
if(this.$ons) {
document?.body?._gestureDetector?.dispose();
}
},
onEnd: (event) => {
if(this.$ons) {
document.body._gestureDetector = new this.$ons.GestureDetector(document.body);
}
},

Related

Adding Click Event Listener to Adobe Data Layer in React

I'm just starting to enter the world of Adobe Analytics. I'm working in React with Typescript and I am trying to leverage the adobe data layer to send information to Adobe Launch. I've been able to successfully use the adobe push function (i.e. window.adobeDataLayer.push({ test: 'test succeeded' })) and can both see that in the console via window.adobeDataLayer.getState() and ran a simple test to confirm it made its way to Adobe Launch.
However, when it comes to adding an event listener, I'm stumped. I attempted to follow Adobe's Documentation and came up with the following (doStuff() was just to confirm that eventListeners were working as expected, which they do):
function myHandler(event: any): void {
console.log("My handler was called")
}
function doStuff() {
console.log('do stuff was called')
}
function adobeAnalyticsTest(): void {
console.log(' adobeAnalyticsTest function called')
window.adobeDataLayer = window.adobeDataLayer || []
window.adobeDataLayer.push({ test: 'test succeeded' })
window.addEventListener('click', doStuff)
window.adobeDataLayer.push(function (dl: any) {
dl.getState()
dl.addEventListener('click', myHandler)
})
}
useEffect(() => {
adobeAnalyticsTest()
}, [])
Looking at window.adobeDataLayer, I couldn't see anything that seemed to indicate there was a click event listener (although this could be ignorance on my part) nor was 'My Handler was called' ever logged to the console. Does anyone have any ideas as to what I'm doing wrong or know how to tell when it's working correctly?
At face value, it looks like you don't have anything in your code that actually calls adobeAnalyticsTest().
Also, the listener you attach to dl doesn't listen for DOM events like clicking on something in window (like your window.addEventListener line); it listens for payloads pushed to adobeDataLayer where the passed event property value matches what you are listening for.
For example, put adobeDataLayer.push({'event':'click'}) in your js console you should see "My handler was called".
Think of it more like subscribing to a CustomEvent (because that's what it is, under the hood), rather than a native DOM event.

How to detect if the React app is actually being viewed

So I have created an app that shows data in realtime obtaining it from devices.
However, I want to make my server not obtain data when nobody is viewing the app.
So essentially I need some way to determine whether the app is currently being viewed, regardless of if it's desktop or mobile, this includes tab is on focus where the app is opened and that is what the user is currently viewing, and there is nothing on top of the browser, so browser opened on the correct tab, but user has explorer on top of it doing something entirely different, this for my case should be false, and for mobile, the same thing including if device is locked (screen off).
The reason for trying to do that, is to reduce the load on the devices, so that data is being requested, only when there is someone to view it.
From what I have researched I found out about the focus and blur events, but I was unable to make it work, and I don't even know if that is the correct approach, but what I have tried is:
Adding event listeners to the window in the App component:
function App() {
useEffect(() => {
window.addEventListener("focus", () => { console.log("viewed")});
window.addEventListener("blur", () => { console.log("hidden")});
})
}
Adding them as props to the App component within index.js:
<App onFocus={() => {console.log("viewed")}} onBlur={() => {console.log("hidden")}}/>
Neither had any kind of effect, I didn't get either of the console outputs.
Is that even the correct approach?
I would add a socket connection to the app. Then the server would be able to know if there are at least X persons connected and act accordingly.
I would suggest you to try socket for this kind of connection tested, but since you also wanna reduce the load for the user, testing if the user is focused in the browser is the way to go.
To achieve it, I won't add this code inside the React component because of the nature of React as all of its components are rendered inside the <div id="root"></div>, other parts of the html page will still be unaffected by this mechanism. So what you probably want to do is to add the code in the index.html and use window.userFocused to pass the value into React from the index
Edit: added focus/blur script
<script>
window.addEventListener("focus", function(event)
{
console.log("window is focused");
window.userFocused = true;
}, false);
window.addEventListener("blur", function(event)
{
console.log("window is blurred");
window.userFocused = false;
}, false);
</script>
So I ended up solving it with pretty much the same code as initiallywith a few slight modifications, I still used an useEffect hook:
const onFocusFunction = () => {
// do whatever when focus is gained
};
const onBlurFunction = () => {
// do whatever when focus is lost
};
useEffect(() => {
onFocusFunction();
window.addEventListener("focus", onFocusFunction);
window.addEventListener("blur", onBlurFunction);
return () => {
onBlurFunction();
window.removeEventListener("focus", onFocusFunction);
window.removeEventListener("blur", onBlurFunction);
};
}, []);
The best way is to use document.
document.onvisibilitychange = () => {
console.log(document.hidden)
}

Change-detection not working properly in ng2 component after navigation via angular1 ui-router

In an application that uses ng-upgrade to use some new ng2 (V2.2.4) components inside a big ng1 (V1.5.9) app (using ui-router) I am currently seeing a very strange change-detection issue. As far as I can tell, this has been introduced in some upgrade of ng2, but sadly I can't easily verify that currently.
I have reduced it to a minimal example by now where i simply have this component:
#Component({
selector:'my-ng2-demo',
template: '<div>{{status}}</div>'
})
export class MyNg2Demo implements OnDestroy {
public status:boolean = true;
private interval:any;
constructor() {
this.interval = setInterval(() => {
this.status = !this.status;
console.log('status: ' + this.status);
}, 2000);
}
ngOnDestroy():void {
clearInterval(this.interval);
}
}
That component is upgraded in the upgrade-adapter and registered as an entry-component in the module.
The component is used in the template of an ng1 controller like this:
<my-ng2-demo></my-ng2-demo>
When I open a browser and navigate directly to that page (the route of the ng1 controller) everything works as expected: the ui shows true/false alternating every 2 seconds.
However: when I navigate away & then come back to the page (visiting some different routes) then suddenly change detection doesn't seem to work. The displayed value alternates only about every 5-6 seconds, seems quite random, although in the console I still see the expected values.
When I change the component's constructor to this:
constructor(private zone: NgZone) {
this.interval = setInterval(() => {
zone.run(() => {
this.status = !this.status;
console.log('status: ' + this.status);
});
}, 2000);
}
It suddenly works again.
Obviously this isn't a feasible solution since the behavior I'm seeing in the real app is much more complex (i would have to add zone.run in dozens of places probably, which would not be maintainable).
I have debugged this for hours and don't understand what is happening.
In Chrome's JavaScript profiler, I basically see that the page idles for almost the whole time in those 5-6 seconds where nothing happens.
This is not a screenshot from that demo-component (but it basically looks the same) but from profiling the tab-component I was initially testing (tab-switching took just as long with no visible actions in between).
update:
After a bit more experimentation what I find quite surprising also is that when instead of putting the status-changing code into a zone.run call, I add a call to ApplicationRef.tick()
(as mentioned here for example: https://stackoverflow.com/a/34829089/1335619 ) it also does NOT work at all.
I don't understand why forcing a complete application-change-detection does nothing, but a zone-run call somehow works.
Example code with tick call which does not work:
constructor(private applicationRef:ApplicationRef) {
this.interval = setInterval(() => {
this.status = !this.status;
console.log('status: ' + this.status);
applicationRef.tick();
}, 2000);
}
There is a bug in the Angular version you are using. Change detection does not work as it should in ng-upgraded apps.
Please refer to https://github.com/angular/angular/issues/12318 for further details.
If you upgrade to 2.4.4, it should resolve the issue.

Open a popover with by ID - Mapbox

In mapbox I am creating my overlays using the following code within my map creation function - http://jsfiddle.net/shanejones/3ajankv9/
I now need to work out a way to open a popover by it's ID in a separate function.
Using the post here I have modified it to the following example which should open layer with id 1.
function next(next_id){
map.featureLayer.eachLayer(function(marker) {
if (marker.feature.properties.id == marker_id) {
marker.openPopup();
}
});
}
But all it does is give me an undefined error anyone know where I'm going wrong here?
Edit - To show the error I get when I run the above function from the console.
Thanks
I ran into this problem in the past. What I ended up doing was something like this, it's not the best solution but it may help you out.
map.featureLayer.eachLayer(function(marker) {
if (marker.feature.properties.id == marker_id) {
marker.fireEvent('click', {
latlng: {
lat: marker._latlng.lat,
lng: marker._latlng.lng
}
});
}
});

Backbone.Marionette - show method not rendering properly.. somethings goes wrong

In my app, I am getting the show method issue. something is wrongly going on with my app. But i couldn't able to find that.
in case if i do like this my view is properly rendering ( but this is wrong approach ):
regions:{
header:'header',
content:'section',
footer:'footer'
},
initialize:function(){
console.log('initialized by layout')
},
renderRegions:function(options){
this.formData = _.defaults(options || {}, requireViews);
if(this.formData.headerView){ //this is true.
this.headerView();
this.renderHeaderView();
}
},
headerView:function(){
this.appHeaderView = new AppHeaderView({model:this.model});
return this.appHeaderView;
},
renderHeaderView:function(){
$(this.header.el).html(this.appHeaderView.render().el) //working fine
//but this is not workig: this.header.show(this.appHeaderView)..why not working?
}
why i use the "this.header.show" - nothing is appending to header.
Any one highlight me what is wrong i do here?
I have simplified my total process, and added in Jsfiddle here is the link:
Live Demo Here
You have a few issues in your code:
A view's model needs to be instantiated, not just the model class.
There is absolutely no reason for you to overwrite the ItemView's render method with what you had.
Your order of operations is wrong. show can only be called after the Layout is in the DOM already.
Here's the main thing that fixes your issue:
var Controller = Backbone.Marionette.Controller.extend({
initialize:function(){
this.layout = new Layout;
$('#wrapper').html(this.layout.render().el);
this.layout.renderRegions();
}
});
Updated FIDDLE
Another option (and something I find myself doing often) is to render the regions using the onShow method of the layout.

Resources