I'm currently setting scrollPositionRestoration: 'enabled' and implementing RouteReuseStrategy that only kicks in when users navigate via next/back button. In safari, scrollPositionRestoration returns to where i was every time. In chrome, some of the time it works, but most of the time it doesn't. I don't really know what's wrong so i'm not posting any codes.
Until I find another way to solve this problem, this is the only solution I found:
-Just add this code to your app-routing.module.ts file,
constructor(router: Router, viewportScroller: ViewportScroller) {
router.events
.pipe(filter((e): e is Scroll => e instanceof Scroll))
.subscribe((e) => {
if (e.position) {
// backward navigation
setTimeout(() => {
viewportScroller.scrollToPosition(e.position);
}, 0);
} else if (e.anchor) {
// anchor navigation
console.log(e.anchor);
viewportScroller.scrollToAnchor(e.anchor);
} else {
// forward navigation
viewportScroller.scrollToPosition([0, 0]);
}
});
}
Related
I'm currently working on a project where I want to show a custom Dialogue box with my Own Content ("Save your data into drafts before leaving"). I have tried different methods but can't find a proper way to do it. I explore all the previous questions on StackOverflow but they didn't work properly in my case.
useEffect(() => {
return () => {
window.onbeforeunload = function() {
return "do you want save your data into drafts before leave?";
};
}
},[])
Currently, I've written the above code in Plain JavaScript to do, but it's just showing the dialogue box on tab close and reload while not showing on custom click events to navigate to other pages or window back button.
React can't help me in this because they remove useBlocker, usePrompt from new releases. How can I achieve it?
One way of doing this is :
import { Prompt } from 'react-router'
const MyComponent = () => (
<>
<Prompt
when={shouldBlockNavigation}
message='Do you want ot save data before leave?'
/>
{/* Component JSX */}
</>
)
If wants on page refresh or browser closing then add:
useEffect(() => {
if (shouldBlockNavigation) {
window.onbeforeunload = () => true
} else {
window.onbeforeunload = undefined
}
},[]);
Second way is to use history if using react-router
useEffect(() => {
let unblock = history.block((tx) => {
// Navigation was blocked! Let's show a confirmation dialog
// so the user can decide if they actually want to navigate
// away and discard changes they've made in the current page.
let url = tx.location.pathname;
if (window.confirm(`Are you sure you want leave the page without saving?`)) {
// Unblock the navigation.
unblock();
// Retry the transition.
tx.retry();
}
})
},[]);
useEffect(() => {
const unloadCallback = (event) => {
event.preventDefault();
event.returnValue = "";
return "";
};
window.addEventListener("beforeunload", unloadCallback);
return () => {
window.addEventListener("popstate", confirmation());
window.removeEventListener("beforeunload", unloadCallback);
}
}, []);
I just did it with this code sample (actually I combine two events to show dialogue whenever users leave a page) and it's working fine for me. Thanks to all of you guys ... Especially #DrewReese for the help
This may be a really simple problem but I can't seem to find why this is happening. I'm trying to develop a SPA in vanilla js using webpack, so far I was able to implement routing
with hashchange event and triggering rerendering. But when I tried to add an active class to the relevant link though when the hash changes, It doesn't work. But when I log to the console, it seems that class was added successfully, but in the HTML it doesn't get updated. Why is this?
this is my hashchange listener,
window.addEventListener("hashchange", (e) => {
const hash = window.location.hash.replace("#", "");
const view = routes.find((route) => {
return route.path == hash;
});
const links = document.querySelectorAll(".nav-list--link");
app.render(view.name);
links.forEach((l) => {
const hashHref = l.getAttribute("href").replace("/#", "");
if (hash === hashHref) {
l.classList.add("active");
console.log(l, l.classList);
} else {
l.classList.remove("active");
console.log(l, l.classList);
}
});
});
And this is the console output,
This is the HTML,
I don't understand why it doesn't update in the HTML if it's shown as updated in Javascript
I'm writing Chrome devtools plugin.
devtools.js
chrome.devtools.panels.create("Override Debug",
null,
"panel.html",
(panel) => {
panel.onShown.addListener(addDebugger);
panel.onHidden.addListener(destroyDebugger);
}
);
So when user navigates to Override Debug tab in devtools, I'm initializing debugger.
When user navigating away from my devtool, I'm discarding debugger - Which is working great
Now the issue comes, when user navigates to Override Debug and closed devtools completely, debugger still alive making page un responsive.
I tried to see events in panel object chrome.devtools objects also tried entire github to see if we have such event. No luck.
Is there any event that monitors devtools close event to discard the debugger I attached?
Update 1
Tried to attach Inspector.enable command as follows but no luck. It never got Inspector.detached message
function addDebugger() {
chrome.tabs.getSelected(null, function(target) {
debuggee = { tabId: target.id };
chrome.debugger.attach(debuggee, "1.2", () => {
chrome.debugger.sendCommand(debuggee, "Network.setRequestInterception", { patterns: [{ urlPattern: '*' }] });
chrome.debugger.sendCommand(debuggee, "Inspector.enable");
});
chrome.debugger.onEvent.addListener((source, method, params) => {
if (source.tabId === target.id) {
if (method === "Network.requestIntercepted") {
// Do many things
} else if (method === "Inspector.detached") {
destroyDebugger();
}
}
})
});
}
Ive enabled deep linking and everything works great when the application opens. When I open the app from a closed state using the url moderatorapp://hello it logs the correct url, but it does not work when the app is deep linked while being opened from a background state. My code is as follows:
componentDidMount() {
// Storage.clear();
Storage.getItem('data_moderator')
.then(_data => {
if (_data && _data.tokens) {
this.autoLogin(_data.tokens);
} else {
Actions.loginForm();
}
}
);
Linking.getInitialURL()
.then(url => {
console.log('Initial Url then ', url);
if (url) {
console.log('Initial Url ', url);
}
})
.catch(error => console.log(error));
Linking.addEventListener('url', this.handleOpenURL);
}
This is obviously because the componentDidMount method is not being called at that point.
What I have tried:
I attempted to wrap the Linking code inside of an event that detects the application entering into the active state and it doesn't work, it logs the same url from the initial attempt when the app was closed. When I attempt to deep link into the app from the background state using the url moderatorapp://goodbye it logs the moderatorapp://hello. So it somehow is not updating.
AppState.addEventListener('change', (state) => {
if (state === 'active') {
console.log('state active');
Linking.getInitialURL()
.then(url => {
console.log('Initial Url then ', url);
if (url) {
console.log('Initial Url ', url);
}
})
.catch(error => console.log(error));
}
if(state === 'background'){
console.log('background');
}
});
Im really new to React Native, any assistance would be greatly appreciated.
Thanks.
https://facebook.github.io/react-native/docs/linking.html Specifically:
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [RCTLinkingManager application:application openURL:url options:options];
}
Apple changed the api for linking so if you are targeting ios 9 or newer, you need this code in your AppDelegate.m file.
The deep linking is working as expected for me even the app is in background. Please check the below specifications.
Node Version : v12.18.x OR Greater
NPM Version : v6.14.x OR Greater
react-native-cli : 2.0.1
react-native : 0.63.x OR Greater
Please check if you have added below line in your AppDelegate.m.
#import <React/RCTLinkingManager.h>
It must be added above #ifdef FB_SONARKIT_ENABLED line. Adding it below this line will cause failing of build while Archiving it for release.
Please check if you have added below code in your AppDelegate.m which is responsible for deep linking.
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [RCTLinkingManager application:application openURL:url options:options];
}
It will work for app cold boot, but it will not work if your app is in background. For this, you need to add below code in your AppDelegate.m
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id> *_Nullable))restorationHandler {
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
This should work irrespective of your AppState: active **OR** background.
This worked for me as expected! Give it a try. This is should definitely work.
Thanks in advance!
I am using twilio API to implement screen sharing in an emberjs app, I am successfully able to share the screen and also toggle on stopping it. Here is my code ->
this.get('detectRtc').isChromeExtensionAvailable(available => {
if (available) {
const { twilioParticipant } = this.get('participant')
if (this.get('stream') && this.get('stream').active) {
this.get('streamTrack').stop()
this.get('userMedia.mediaStream')
.removeTrack(this.get('streamTrack'))
this.set('isEnabled', false)
twilioParticipant.removeTrack(this.get('streamTrack'))
} else {
this.get('detectRtc').getSourceId(sourceId => {
// "cancel" button is clicked
if (sourceId !== 'PermissionDeniedError') {
// "share" button is clicked extension returns sourceId
this.get('userMedia')
.getScreen(sourceId)
.then(mediaStream => {
this.set('isEnabled', true)
this.set('stream', mediaStream)
this.set('streamTrack', mediaStream.getVideoTracks()[0])
twilioParticipant.addTrack(mediaStream.getVideoTracks()[0])
})
.catch(() => { /* do nothing, but return something */ })
}
})
}
} else {
this.get('flash').status(
'base',
this.get('intl').t('chromeExtension.install'),
{
icon: 'alert-circle',
push: true
}
)
// TODO Show the system popup to install chrome extension from web store
// !!chrome.webstore &&
// !!chrome.webstore.install &&
// chrome.webstore.install(this.webStoreUrl)
}
})
The issue I'm facing is with the stop sharing button which is at the bottom of the app as seen in screenshot below
I need a way to listen to an event handler and execute the some code after clicking on the stop sharing screen button, I know there is an onended event Handler which is mentioned in the MediaStreamTrack docs, but I don't know how to use it, any help will be highly appreciated.
https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack
The "stop sharing" button will trigger the MediaStreamTracks 'ended' event. Try this:
mediaStream.getVideoTracks()[0].addEventListener('ended', () => console.log('screensharing has ended'))
for some reason, #philipp answer is not working for me and I found this quite helpful
https://github.com/webrtc/samples/blob/gh-pages/src/content/getusermedia/getdisplaymedia/js/main.js#L88
this.get('stream').addEventListener('inactive', e => {
console.log('Capture stream inactive - stop recording!');
});