-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optionally preserve existing url on sending routed signal with upload. #56
Comments
Hm, I do not think I completely understood the scenario. Do you have some small code snippets? Where you define the url, trigger the signal and where you store the state? :-) @Guria should probably also get in on this |
Triggering events in the controller with pagination: onLimitChange = (e, index, limit) => {
this.props.signals.onLimitChanged({ limit });
// queryJSON - object from state, it's parsed with URLON current url.
// here I merge it with new query params, to preserve other parts of query (e.g. search string)
this.props.signals.pageUsersOpened(Object.assign({}, this.props.queryJSON, { page: 1 }, { limit }));
}
onPageChange = (page) => {
if (page > 0 && page <= this.props.pagination.pagesAmount) { // in case of glitches with button deactivation
this.props.signals.onPageChanged({ page });
// and here I want to save 'limit' part of query. without merging there will be only number of page
this.props.signals.pageUsersOpened(Object.assign({}, this.props.queryJSON, { page }));
}
} Thank you for the response. |
I'll try to look forward with this in nearest time. |
Aha, so if I understand this correctly. You have a url with query |
Yes, exactly. |
I had thoughts on this case. Would present my suggestion soon. |
It would be great, for me it is pretty typical use case. |
I read more careful. Seems I was thought about slightly different case, like global query parameter ( Router(controller, routes, {
globalParams: {
lang: ['lang']
}
}) Then router would exclude Can you tell more about splitting |
Mapping query parameters to state path is a good idea, I think. But it's important to keep correct and simple flow of data of cerebral. I mean, to update state in a right moment. Maybe it will be simpler to manage dehydration and rehydration of the state with such mapping (it's other story I suppose...). Regarding |
Why you have separate
As I said above, it is hard to acheive it because route is bound to one signal a time. |
Moved out global params as separate issue to discuss #58 |
@Guria and @freele , yes, if you have a query in your url that has information about the state I would suggest creating a signal that supports it. So: controller.signal('tableQueryChanged', chain); And: onPageChange(page) {
const limit = this.props.limit;
const filter = this.props.filter;
this.props.signals.tableQueryChanged({limit, page, filter})
}
onLimitChange(page) {
const page = this.props.page;
const filter = this.props.filter;
this.props.signals.tableQueryChanged({limit, page, filter})
} And your chain sets all of them every time. The way the router works conflict with how we traditionally think sometimes. It is interesting to look at these scenarios and how we can solve them :-) Lets just iterate on this and I am sure we will find a common ground! |
@Guria, thank you. Yes, in my case state is updated in |
Main idea that signals shouldn't relay on payload source. It just receive it no matter if it from url or direct call. But app developer is free to define how signals payload mapped to url. |
Hm, yeah. I am just very unsure how to keep this simple. I think maybe we should expose a new method on signals bound to the router. Like: // Instead of, which overrides
this,props.signals.pageChanged({page: 12});
// You would, which keeps current query
this,props.signals.pageChanged.keepQuery({page: 12});
// Or expose an option object
this,props.signals.pageChanged({page: 12}, {
keepQuery: true
}); Really bad name, but that way it is explicit. Instead of passing options somewhere else. It is very likely that you debug the signal fired to understand how the url was created, so it is a good place to put it. If it covers all scenarios |
As this is being discussed just adding: this.props.signals.someSignal({page: 12}, {mergeQuery: true});
// Or
module.addSignals({
someSignal: {
chain: [],
mergeQuery: true
}
}) I think this is a good convention of adding any options to signals. You can add it "on the fly" or you can set it on the signal definition. This allows modules affected to hook on to the options as well to react to them. Meaning that modules would be able to empower signals with new options. Like in this example, the router does |
@christianalfoni I suppose that we will need to know which query should be merged and which not. Eg, while navigating from one module to another is most likely we will need to replace query. |
Like the idea of having a unified way for modules in general! Maybe those options should be wrapped in parameter?
|
@maxfrigge @christianalfoni says that chain is also option. And it already works like this. |
Oh.. i thought its the object way of setting a signal and chain is the action chain. Isn't this how you define sync signals with new api? |
exactly. it is the same syntax: module.addSignals({
someSignal: {
chain: [action1, action2],
mergeQuery: true,
isSync: true
}
}) |
Ah.. I understood that by setting:
You define that when calling the signal in a view.. you can pass the option The way you are proposing it it's "just a router thing", but wouldn't it be good to have a generic way to deal with such things so that it's not tied to the router module. Or would this still be possible? |
The only difference is you are adding extra options property. @christianalfoni said me that every property in object used as signal definition is already option. Even |
ok. cool. than stick with that :) |
Just confirming that object is "options". So can attach whatever we want directly to root of object :-) |
What is the status here now? :) |
Planned to make expiremetal implementation. |
function wrapSignal(signal) {
var prevPayload = {}
return function (payload, options) {
if (options.merge) {
payload = Object.assign({}, prevPayload, payload)
}
prevPayload = payload
delete options.merge
signal(payload, options)
}
}
someGridOpened = wrapSignal(this.props.signals.someGridOpened)
someGridOpened({
page: 0,
filter: '',
sort: [
{ field: 'fieldA', dir: 'ASC' }
]
})
someGridOpened({ filter: 'bla bla' }, { merge: true }) Pros
Cons
|
function wrapSignal(signal) {
var prevPayload = {}
function wrappedSignal (payload, options) {
if (options.merge) {
payload = Object.assign({}, prevPayload, payload)
}
prevPayload = payload
delete options.merge
signal(payload, options)
}
wrappedSignal.merge = function (payload) {
return Object.assign({}, prevPayload, payload)
}
return wrappedSignal
}
someGridOpened = wrapSignal(this.props.signals.someGridOpened)
someGridOpened({
page: 0,
filter: '',
sort: [
{ field: 'fieldA', dir: 'ASC' }
]
})
someGridOpened({ filter: 'bla bla' }, { merge: true })
<Link signal={this.props.signals.someGridOpened} params={ someGridOpened.merge({ page: 1}) }>
Next Page
</Link> Pros
|
function wrapSignal(signal) {
var prevPayload = {}
function wrappedSignal (payload, options) {
if (options.merge) {
payload = Object.assign({}, prevPayload, payload)
}
prevPayload = payload
delete options.merge
signal(payload, options)
}
wrappedSignal.signalName = signal.signalName
return wrappedSignal
}
someGridOpened = wrapSignal(this.props.signals.someGridOpened)
someGridOpened({
page: 0,
filter: '',
sort: [
{ field: 'fieldA', dir: 'ASC' }
]
})
someGridOpened({ filter: 'bla bla' }, { merge: true })
<Link signal={someGridOpened} params={{ page: 1 }} options={{ merge: true }}>
Next Page
</Link> Pros
Cons
|
// cerebral-module-signal-merge-prev-payload-option
function (module, controller) {
var store = {}
controller.on('signalTrigger', function (event) {
if (event.signal.options.merge) {
var prevPayload = store[event.signal.signalName] || {}
store[event.signal.signalName] = event.signal.input = Object.assign(prevPayload, event.signal.input)
delete event.signal.options.merge
}
})
module.addServices({
dropStore: function () { store = {} }
})
} Pros
Cons
|
// cerebral-module-signal-merge-prev-payload-option
function (module, controller) {
var store = {}
controller.defaultOptions.context.push(function (context, execution) {
if (execution.signal.options.merge) {
var prevPayload = store[event.signal.signalName] || {}
store[event.signal.signalName] = event.signal.input = Object.assign(prevPayload, event.signal.input)
}
})
module.addServices({
dropStore: function () { store = {} }
})
} Pros
Cons
|
Hi @Guria I think this is the cleanest implementation: <Link signal={someGridOpened} params={{ page: 1 }} options={{ merge: true }}>
Next Page
</Link> I think it is wise to keep the router as one module for now and keep using these options. I think it is a simple concept that you can see all over. Creating a single signal, general options for all signals, options passed on Link etc. It is the same "options object". There is still a discussion on how these options should be passed to the debugger. Eyh... maybe we should just: controller.on('anyEvent', ({signal, options, [action]) {
}); So we pass the options as its own argument. That way also the debugger can just pick out any options it wants to pass it to the debugger. Yes... I think this is it! :-) What do you think? |
cc @freele how are you feeling with this suggestions? does it solves your case? |
@Guria Yes, I think that it what was needed. As I see, both suggestions answer the initial request. Thanks for this. |
This would allow to implement modules each one of which will add its part to url, not disturbing the rest part of the url.
For example, I have 'pagination' module and 'search' module. They both have to add some parameters to the query in the url. But now for preserving the url I have to keep it in my state and merge it with new upload before sending routed signal (and merged version goes as upload).
Maybe it can be useful to add a setting to the router, which will keep url and merge signal's upload to existing url rather than overwriting it?
The text was updated successfully, but these errors were encountered: