UI-Router Reload State without a full page refresh - angular-ui-router

Currently if I want to reload a state, I have to use the $state.reload(). This causes a full page refresh, which is very unfriendly. I am looking for a way to just re-resolve my dependencies and reset the controller. Is this possible?

Just to add on #Dag 's answer:
Do note, as of 0.2.14 you also have an option to just reload the current state and not it's parent.
So $state.go(people.search, {}, {reload: true}); would reload the people state as well as all its childs.
While $state.go(people.search, {}, {reload: "people.search"}); would not reload the people state but would reload people.search and its childs.

you can try with:
$state.go($state.current.name, $state.params, { reload: true });
it will force transition even if the state or params have not changed without full page refresh. you can pass the state + the params + reload options.
for details look here at "go" method.

Related

How can I check element attribute after click before redirect?

I have a simple login form and I need to check whether button becomes disabled after clicking on it. The issue is that after click on submit, redirect happens, causing assertion step to fail due to element being detached from the DOM. My question is whether it is possible to somehow check visibility attribute of the element after click.
cy.get('[data-cy="email"]').type(this.user.email);
cy.get('[data-cy="password"]').type('valid');
cy.get('button[type="submit"]').click().should('be.disabled'); // this fails due to dettachment from the DOM.
I've attempted to use .then() after click, but that did not help. Using cy.intercept() is also not an option due to how app is written.
Thank you for any idea.
You can do this:
cy.get('button[type="submit"]').click()
cy.get('button[type="submit"]').should('be.visible').and('be.disabled')
When you get the message "element is detached from DOM", it means an action on the page (in this case submit event) has replaced the element with a new version.
If you want to check that the old version of the element has the disabled attribute, this kind-of works.
cy.get('button[type="submit"]')
.click()
.should($el => {
const disabledAttr = $el.attr('disabled')
expect(disabledAttr).to.eq('disabled')
})
But I think this would be flaky if there is a delay between .click() and the disabled attribute getting applied.
If you want to check that the new version of the element has the disabled attribute, this should work.
cy.get('button[type="submit"]').click();
cy.get('button[type="submit"]').should('be.disabled'); // runs after "page load" event

history.replaceState() not working with history.scrollRestoration = 'auto' in Svelte/Sapper

I am using history.replaceState() to update the query params of my page without causing a page reload as suggested in this SO answer.
function setQueryParam ({ name, value }) {
const params = new URLSearchParams(window.location.search)
params.set(name, value)
history.replaceState({}, '', decodeURIComponent(`${window.location.pathname}?${params}`))
}
I am also storing the scroll position of the user with the following line:
history.scrollRestoration = 'auto'
When navigating from one page to another, scrollRestoration works fine - the scroll position is maintained between pages. However, after I change the query params with my setQueryParam function, scroll restoration no longer works.
Why is this happening?
Note: the same code works fine outside of Svelte/Sapper, using HTML and JavaScript only.
As a client-side router, Sapper has to hijack scroll management & restoration a good deal to emulate the behaviour you normally get when you fully reload the browser on each page change.
To do that, it uses history's state to know the scroll position to restore.
When you're using history.replaceState, you're changing the state (it's the first argument you place to replaceState). And so, Sapper don't find its restore scroll data when you later pop the state.
You can try to manually preserve the history state like this:
// notice the first argument
history.replaceState(history.state, '', decodeURIComponent(`${window.location.pathname}?${params}`))
I don't think history.scrollRestoration actually has any effect in Sapper.

How do I refresh a view?

I'm refreshing my view model onRouteMatched...
_onRouteMatched: function(oEvent) {
this.getView().setModel(new JSONModel({siteInfo: {}, surveyInfo: {}, categories: []}), "view");
var oViewModel = this.getView().getModel("view");
}
However, if I'm returning to the page without refreshing (by pressing the back arrow and then returning), I'm getting a duplicate ComponentId error when creating the view again.
var oPanel = new sap.m.Panel({
expandable: true,
expanded: false,
headerText: oData.results[0].CategoryDesc,
id: "Panel" + index
});
It's as though the view component "Panel" still exists, so that a new one can only be created on refresh, not onRouteMatched.
This works fine if I refresh the page, but how can I get the view to refresh on onRouteMatched?
Simply avoid programmatical controls creation (by coding) and try to define all the stuff right it the XML view and make use of bindings - it's a very powerfull feature that can solve 99% of your problems.
You define binding once and change the view only via data modifications in the model, but not via the DOM manipulation (bindings will do it for free based on the model state).
I'd recommed you to go throught the data binding tutorials in the official documentation.
As for your problem, if to imagine the solution without bindings, you should always destroy the stuff manually and recreate it again. Or perform some existence checks.

how to scroll to the loaded ui-view

I have a ui-view inside of my page.
When some button is clicked, the ui-view is loaded and replaced by some HTML.
I want the page to be scrolled down to the just-loaded part of the page.
Is this possible?
Thanks in advance
The ui-router module has been updated to scroll to the ui-view by default. You can add the autoscroll="false" attribute on <div ui-view> to prevent this. The default setting is true which scrolls to the ui-view upon state change.
I would think it should be the other way around where you have to set the autoscroll to enable rather than disable but this is the functionality of the updated ui-router.
You can read about it here.
In the linked Github issue, it says that the default value is autoscroll="expr" but I have found that expr does nothing and that the default value is autoscroll="true" (which makes more sense).
On Route change it will scroll to the top of the page.
$scope.$on('$routeChangeSuccess', function () {
window.scrollTo(0, 0);
});
put this code on your controller. (Change the value as per your requirements)

Google Chrome Extension - How can I include a content script more than once?

I've been working on Chrome Extension for a website for the past couple of days. It's coming along really nicely but I've encountered a problem that you might be able to help with.
Here's an outline of what the extension does (this functionality is complete):
A user can enter their username and password into the extensions popup - and verify their user account for the particular website
When a user browses http://twitter.com a content script is dynamically included that manipulates the DOM to include an extra button next to each tweet displayed.
When a user clicks this button they are presented with a dialog box
I've made a lot of progress but here is my problem:
When a user visits Twitter the content script is activated and all tweets on the page get my new button - but if the user then clicks 'More...' and dynamically loads the next 20 tweets... these new additions to the page DOM do not get affected by the content script (because it is already loaded).
I could add an event listener to the 'More...' button so it then triggers the original content script again (and adds the new button) but i would have to predict the length of twitter's ajax request response.
I can't tap into their Ajax request that pulls in more tweets and call my addCurateButton() function once the request is complete.
What do you think is the best solution? (if there is one)
What you want to do is to re-execute your content-script every time the DOM is changed. Luckily there is an event for that. Have a look at the mutation event called DOMNodeInserted.
Rewrite your content script so that it attaches an event listener to the body of the DOM for the DOMNodeInserted event. See the example below:
var isActive = false;
/* Your function that injects your buttons */
var inject = function() {
if (isActive) {
console.log('INFO: Injection already active');
return;
}
try {
isActive = true;
//inject your buttons here
//for the sake of the example I just put an alert here.
alert("Hello. The DOM just changed.");
} catch(e) {
console.error("ERROR: " + e.toString());
} finally {
isActive = false;
}
};
document.body.addEventListener("DOMNodeInserted", inject, false);
The last line will add the event listener. When a page loads the event is triggered quite often so you should define a boolean (e.g. var isActive), that you initialize to false. Whenever the inject function is run check whether isActive == true and then abort the injection to not execute it too often at the same time.
Interacting with Ajax is probably the hardest thing to coax a content script to do, but I think you’re on the right track. There are a couple different approaches I’ve taken to solving this problem. In your case, though, I think a combination of the two approaches (which I’ll explain last) would be best.
Attach event listeners to the DOM to detect relevant changes. This solution is what you’ve suggested and introduces the race condition.
Continuously inspect the DOM for changes from inside a loop (preferably one executed with setInterval). This solution would be effective, but relatively inefficient.
The best-of-both-worlds approach would be to initiate the inspection loop only after the more button is pressed. This solution would both avoid the timing issue and be efficient.
You can attach an event-handler on the button, or link that is used for fetching more results. Then attach a function to it such that whenever the button is clicked, your extension removes all the buttons from DOM and starts over inserting them, or check weather your button exists in that particular class of DOM element or not and attach a button if it doesn't.

Resources