Prevent LWC component destruction on NavigationMixin.Navigate - salesforce

I have a page with a Lightning Web Component that calls
this[NavigationMixin.Navigate]({
type: 'standard__recordPage',
attributes: {
recordId: id,
objectApiName: 'myobject__c',
actionName: 'edit'
}
}, true);
The edit pop-up modal then shows overlaid on the page. If I hit cancel, close, or save on the modal the entire original LWC re-renders, eg the constructor, connectedcallback, and renderedcallback are all called a second time.
Why is this happening? Shouldn't the renderedcallback be the only lifecycle event to be invoked a second time?

Related

Triggering global behavior for a "loading" component such as with Angular 1's $emit

I'm making a loading overlay component in Angular 2, and I realized, I'm not sure how to trigger it. In Angular 1, I would emit something and listen in the loading spinner directive, to hide or show. In Angular 2, I suspect I need to be doing this via a service, but I can't figure out how the architecture would work. How would the service then communicate with the loading spinner component? I suspect this is a case for observables, but being new to this side of things, I can't figure out how to structure this. Any advice is appreciated.
Here's a slightly more detailed answer following RhoVisions' comment.
Typically, you would inject a service in both the spinner component and any component that requires to show/hide the spinner.
The service acts as some kind of "event bus" and can be implemented with a (Behavior)Subject, which is a special kind of observable that can both emit values (on the triggering component's side) and subscribe to emitted values (on the spinner component's side).
Here's a rough outline for the implementation:
The spinner service:
#Injectable()
export class SpinnerService {
private spinnerEvents: BehaviorSubject<string> = new BehaviorSubject<string>('hide');
show() {
this.spinnerEvents.next('show'); // emit value
}
hide() {
this.spinnerEvents.next('hide'); // emit value
}
get events() {
// Expose the subject as an observable for subscribers.
return this.spinnerEvents.asObservable();
}
}
The spinner component:
#Component({
template: `<div [hidden]="!showSpinner">SPINNER</div>`
})
export class SpinnerComponent {
showSpinner: boolean;
constructor(ss: SpinnerService) {
// Set the `showSpinner` flag to true/false depending on event received.
ss.events.subscribe(event => this.showSpinner = (event == 'show'));
}
}
Some component using the spinner:
#Component({ ... })
export class SomeComponent {
constructor(ss: SpinnerService) {
// Manually trigger show/hide events.
ss.show();
// ...Some instructions...
ss.hide();
}
}
Here is exactly what you are trying to do. I'm using the same thing.
https://github.com/colinjlacy/angular-2-loading-indicator

backbone.history.naviguate trigger router staying on the same page

My problem is pretty simple.
I start on /app, when I click on some button I trigger /report with
Backbone.history.navigate('report',{trigger: true, replace: true});
Then I'm on /report page. No problem.
I have the same button on /report and I would like to trigger router route "report" when i click on it. It seems it's not working because I'm already on the asked page.
Any idea how I should proceed ?
thanks a lot
Backbone.history.navigate('report',{trigger: true, replace: true});
You should not be using this to render/reload your application views.This is not recommended.
Rather you should have a controller object (a js object) which extends Backbone.Events
Define a callback for the for the route "/report" as follows:
var MyAppBus = _.extend({},Backbone.Events);
MyAppBus.on("report",function(payLoad){
// 1.Load the data
// 2.Create an instance of the view passing the loaded data.
// (In your case, you could also pass an instance of the view in the payload
// and update the data alone in the view instance.)
// 3.Render the view.
// 4.Call the router navigate function with trigger set to false to
// update the url on a need basis.
});
Now, in the event/router callback you can do something like this:
MyAppBus.trigger("report",payLoad);
Where payLoad in the event callback could be:
var payLoad = {};
payLoad.view = viewInstance;

Ext.util.KeyMap destroy method

init: function(){
this.callParent(arguments);
map = new Ext.util.KeyMap(Ext.getBody(),{
key: Ext.EventObject.F8,
scope: this,
target:this,
fn: this.onKeyPress
});
}
In the init method takes subscription on event. Is there a method, when I leave the page to perform map.destroy?The problem is when I go to a page occurs subscription event and pressing the F8 works everywhere. How to make that worked only on this page?
This behavior happens because you are targeting Ext.getBody() with your KeyMap.
Even though target points to this, you are adding it Ext.getBody() before, that means that no matter where you are on the page, the KeyMap will work.
So you have two options:
1) Assign your component element to your target. Note that the method onKeyPress will only be called if there is something selected in your component element.
Example:
If you set target: component.getEl(), the onKeyPress method will only be called if you press F8 while a textfield is focused inside your panel.
2) Keep adding it to Ext.getBody() if you want the onKeyPress method to be called no matter if there is anything focused on the page. But if it has to work only when a specific page is active, you should add conditionals to your onKeyPress method.
Example:
onKeyPress : function() {
currentTab = this.getActiveTab();
if (currentTab.title=='Foo') {
console.log('You hit F8');
}
}
Here is fiddle demonstrating the process: https://fiddle.sencha.com/#fiddle/g7a

onClick event isn't firing on React Component

I'm working on a component stub where I have a grid of tiles, each that require a click handler, and also a specific "new" tile that has a different click handler. I'm trying to get the click handlers working correctly, but the event never seems to fire.
Any ideas?
var grid = React.createClass({
onCreateNew: function () {
console.log("onCreateNew");
},
render: function () {
var tiles = [];
if (this.props.items) {
tiles = this.props.items.map(function (item, index) {
//create a tile for each item
});
}
//always append "new" tile for the last one
tiles.push(React.DOM.div({
onClick: this.onCreateNew, className: "tile new_tile"
},
React.DOM.div({ className: "plus", onClick: this.onCreateNew }, "+")
));
return React.DOM.div({ id: "flowsheetPane" }, tiles);
}
});
As commenters have mentioned, your code appears to work as expected in isolation.
React delegates to event handlers with a single event listener at the root of the DOM, so events need to propagate all the way to the top in order for React to call your function.
Could you have added some event listeners somewhere in the component hierarchy that are calling event.stopPropagation()? If you did this outside of React (e.g. natively or with jquery), it would cause the events to never reach the top of the DOM, and React would never have a chance to delegate out to your methods.

App switching between views

I'm trying to have an app switch between views, depending on whether a user is logged in or not. The app will try to load the main view first, and then in one of the controller's launch functions will swap to the login form if you are not logged in. This part isn't having any problems.
The problem is that when the user fills out the login form and logs in, the view does change to the main view, but it does not receive events (clicking the logout button does nothing.) I know this is not a problem with the view itself, because if the main view is loaded without switching to the login screen, it will detect clicking the logout button.
In one of my controllers:
launch: function() {
this.session = localStorage.getItem('session');
if(!this.session) {
Ext.Viewport.remove(Ext.Viewport.getActiveItem(), true);
Ext.Viewport.add(Ext.create('App.view.Login'));
}
},
And when the login happens, I switch to the main view like so (which includes the logout button)
Ext.Viewport.remove(Ext.Viewport.getActiveItem(), true);
Ext.Viewport.add(Ext.create('App.view.Main'));
Ext.Msg.alert('Logged In', 'Login successful.');
So I found the not obvious at all answer: when defining the events in the controller, I needed to add button before the identifiers, example:
config: {
refs: {
loginForm: 'loginForm',
logoutForm: 'logoutForm'
},
control: {
'button#loginButton' : {
tap: 'onLogin'
},
'button#logoutButton' : {
tap: 'onLogout'
}
}
},

Resources