how does aurajs sandbox.on() and sandbox.emit() works? - backbone.js

I am new to auraJS and have gone through documentation but did not understand what is the role of sandbox in application. According to docs sandbox.on() is subscriber(listener) and sandbox.emit is publisher. but what are the argument passed in these functions and how i can call a function of other component with sendbox.emit(). i have code in the application like
sandbox.emit('layout:add-requested', this.collection, layoutModel);
and through debugging i come to know above line of code calls renderAddLayout() of other component's view. but i could not find any relationship or asynchronous call which can trigger the renderAddLayout() function();

Related

Update Event with Fullcalendar in React

So I am trying to work with FullCalendar and I want to have the user be able to edit an event details, click update and I locally update the event and then push it up to the server. I have the following code, but the issue is when there are multiple changes, is calling the event callback multiple times. Is there a way I could do this just once to save on many API calls? Here is the code I have
let currentEvent = calendarApi.getEventById(eventId);
currentEvent.setExtendedProp('notes', notes);
currentEvent.setExtendedProp('person', person);
Maybe there is a different method I am just not seeing in the docs?
The undocumented mutate method that's used to implement setExtendedProp accepts an object that can have multiple properties. You could use it like this:
event.mutate({
extendedProps: {
notes: notes,
person: person,
},
})
or, using object property value shorthand:
event.mutate({extendedProps: {notes, person}})
I have absolutely no experience with fullcalender though, so use at your own risk!

In React, how would i convert certain aspects of a stateful component to work within a function component?

My code is in React & is quite extensive, so i have provided a codesandbox link: My transactions section of my "under construction" app: https://codesandbox.io/s/agitated-sea-96048. A Chegg expert had given me the code that renders what you'll see above my transaction cards (his ModalEdit, for now, was placed inside of the TransactionsLayout component--this is just so you can visualize, somewhat, of what i'm looking for).
i like the way that the edit does what my question is asking. however, i do not know how to make it work within the framework of my app, because my TransactionCard.jsx file is a function component without state. and, the expert's code is with state.
i have tried putting his code as a separate component & calling to it with the button onClick (line#69 on the TransactionsCard.jsx file). however, this doesn't work because i can't figure out 'how' to convert his code to work within the framework of the transactions' files.

React server side renderer omits setState callback function?

I'm trying to use the second parameter of setState to pass a callback function, but it appears (from what I can gather) that the server-side renderer ignores this parameter completely. I'm using Gatsby which utilizes server-side rendering to build a static React-based site. My call is in an onChange handler, and looks like this:
this.setState({ [event.target.name]: event.target.value }, () => { console.log('setState callback') })
The state is updated as expected, but the callback is never called. Note: The same issue applies whether I pass an object or a function for the first parameter. The component function looks like this:
ReactComponent.prototype.setState = function (partialState, callback) {
[...]
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
That updater's method, which lives in ReactUpdateQueue.js (according to the call stack) looks like this:
enqueueSetState: function (publicInstance, partialState)
I don't fully understand the build process for React, but I believe that method/file is coming from this file in the source:
/src/renderers/shared/server/ReactPartialRenderer.js
The only other place I can find this function defined is here:
/src/isomorphic/modern/class/ReactNoopUpdateQueue.js
enqueueSetState: function(
publicInstance,
partialState,
callback,
callerName,
) {
warnNoop(publicInstance, 'setState');
}
which looks like the correct method signature, but doesn't appear anywhere in the call stack when I debug the setState call in my code. This doesn't appear to be a problem with client-side rendered React components (I'll try to set up a simple repo to show this issue, but it doesn't appear replicable on CodePen etc.) I know I could use componentDidUpdate to accomplish what I need to do, but the callback is much more convenient in my instance, and I hate leaving a mystery like this unsolved. :)
Well, I figured it out, and turns out, as is too often the case, this was a self-inflicted error. The default Gatsby install uses React v15 but we wanted to use 16, so we added a direct dependency to it in package.json, which got built in to the resulting package. I still don't quite understand why the above mentioned version of enqueueSetState was called instead of the proper one, but removing the reference to react (and adding gatsby-plugin-react-next, which does what we want by simply pointing webpack to the newer version) fixed the issue.
At least this was a good excuse to get a little more familiar with the guts of React. Perhaps this will save somebody else some time in the future.

What is difference between method `toHaveBeenCalled()` and `andCalledThrough()`

While using the Jasmine Spies, how different is andCalledThrough() method from toHaveBeenCalled, does it actually run the original method completely? Any ideal scenarios when I should use it?
These are two different steps in spying on a function.
When you declare a spy on a function, before the function is called, you can attach some instructions to what should be done when the function is called. and.callThrough() means that the actual implementation will be used. Other options are and.callFake() and and.returnValue(), which allow you to mock a response and not use the actual implementation.
After the function you spied on was called, you can verify it was called using expect and toHaveBeenCalled and its variations.
Please refer to the documentation.

Why is it considered bad practice to call trigger: true in the navigate function of backbone.js?

I have read in several places that calling the Backbone.history.navigate function is considered bad practice.
For example Addy Osmani sais in his book "Developing Backbone.js Applications"
It is also possible for Router.navigate() to trigger the route along
with updating the URL fragment by passing the trigger:true option.
Note: This usage is discouraged...
http://addyosmani.github.io/backbone-fundamentals/#backbone.history
Or Derick Bailey in his blog post even sais:
You shouldn’t be executing the route’s handler from within your application, most of the time.
But I don't really understand the reasoning behind it and what would be a better solution.
In my opinion it is not really bad to call the navigate function with the trigger:true option. The route function could upon calling always check if the considered data is already loaded and show this loaded data instead of doing the whole work all over again...
There seems to be some confusion about what Router#navigate does exactly, I think.
Without any options set it will update the URL to the fragment provided.
E.g. router.navigate('todo/4/edit') will update the URL to #todo/4 AND will create a browser history entry for that URL. No route handlers are run.
However, setting trigger:true will update the URL, but it will also run the handler that was specified for that route (In Addy's example it will call the routers editTodo function) and create a browser history entry.
When passing replace:true the url will be updated, no handler will be called, but it will NOT create a browser history entry.
Then, what I think the answer is:
the reason why the usage of trigger:true is discouraged is simple, navigating from application state to application state to application state requires most of the time different code to be run than when navigating to a specific application state directly.
Let's say you have states A, B and C in your application. But state B builds upon state A and state C builds upon B.
In that case when you navigate from B to C only a specific part of code will need to be executed, while when hitting state C directly will probably execute some state checking and preparation:
has that data been loaded? If not, load it.
is the user logged in? If not redirect.
etc.
Let's take an example: State A (#list) shows a list of songs. State B (#login) is about user authentication and state C (#list/edit) allows for editing of the list of songs.
So, when the user lands on state A the list of songs is loaded and stored in a collection. He clicks on a login-button and is redirected to a login form. He successfully authenticates and is redirected back to the song list, but this time with delete-buttons next to the songs.
He bookmarks the last state (#list/edit).
Now, what needs to happen when the user clicks on the bookmark a few days later?
The application needs to load the songs, needs to verify the user is (still) logged in and react accordingly, stuff that in the state transition flow had already been done in the other states.
Now for a note of my own:
I'd never recommend the above approach in a real application as in the example. You should check whether the collection is loaded when going from B to C and not just assume it already is. Likewise you should check whether the user really is logged in. It's just an example.
IMO the router really is a special kind of view (think about it, it displays application state and translates user input into application state/events) and should always be treated as such. You should never ever rely on the router to transition between states, but rather let the router reflect the state transitions.
I have to disagree with #Stephen's answer here. And the main reason why is because the use of router.navigate({trigger : true}) gives the router responsibility to handle the application's state. It should only reflect application state, not control it.
Also, it is not a View's responsibility to change the hash of the window, this is the router's only job! Don't take it away from it! Good modularity and separation of concerns makes for a scalable and maintainable application.
Forwarding a person to a new section within your application
Backbone is an event driven framework, use events to communicate. There is absolutely no need to call router.navigate({ trigger : true }) since functionality should not be in the router. Here is an example of how I use the router and I think promotes good modularity and separation of concerns.
var Router = Backbone.Router.extend({
initialize: function(app) {
this.app = app;
},
routes: {
'videoLibrary' : function() { this.app.videoLibrary(); }
}
});
var Application = _.extend({}, Backbone.Events, {
initialize: function() {
this.router = new Router( this );
this.listenTo( Backbone, 'video:uploaded', function() {
this.router.navigate('/videoLibrary');
this.videoLibrary();
});
},
videoLibrary: function() {
//do useful stuff
}
});
var uploadView = Backbone.View.extend({
//...
uploadVideo: function() {
$.ajax({
//...
success: function() { Backbone.trigger('video:uploaded'); }
});
}
});
Your view does not need or want to know what to do when the user is done uploading, this is somebody else's responsibility. In this example, the router is just an entry point for the application's functionality, an event generated by the uploadView is another. The router always reflects the application state through hash changes and history but does not implement any functionality.
Testability
By separating concerns, you are enhancing the testability of your application. It's easy to have a spy on Backbone.trigger and make sure the view is working properly. It's less easy to mock a router.
Modules management
Also, if you use some module management like AMD or CommonJS, you will have to pass around the router's instance everywhere in the application in order to call it. Thus having close coupling in your application an this is not something you want.
In my opinion it's considered bad practice because you should imagine a Backbone application not like a Ruby On Rails application but rather like a Desktop application.
When I say RoR, I'm just saying a framework supporting routing in sense that a route brings you to a specific call to the controller to run a specific action (imagine a CRUD operation).
Backbone.history is intended just as a bookmark for the user so he can, for example, save a specific url, and run it again later. In this case he will find the same situation he left before.
When you say:
In my opinion it is not really bad to call the navigate function with
the trigger:true option. The route function could upon calling always
check if the considered data is already loaded and show this loaded
data instead of doing the whole work all over again...
That to me sounds smelly. If you are triggering a route and you are checking for the data to see if you have it, it means that you actually already had them so you should change your view accordingly without loading again the entire DOM with the same data.
That said trigger:true is there so do we have reason use it? In my opinion it is possible to use it if you are completely swapping a view.
Let's say I have an application with two tabs, one allows me to create a single resource, the other one let me see the list of the created resources. In the second tabs you are actually loading a Collection so data is different between the two. In this case I would use trigger:true.
That said I've been using Backbone for 2 weeks so I'm pretty new to this world but to me it sounds reasonable to discourage the use of this option.
It depends on your context.
If you have done something in your current view that might affect the view you are about to navigate to, for example creating for deleting a customer record, then setting trigger to true is the right thing to do.
Think about it. If you delete a customer record don't to want to refresh the list of customers to reflect that deletion?

Resources