offirgolan / ember-parachute Goto Github PK
View Code? Open in Web Editor NEWImproved Query Params for Ember
Home Page: https://offirgolan.github.io/ember-parachute
License: MIT License
Improved Query Params for Ember
Home Page: https://offirgolan.github.io/ember-parachute
License: MIT License
I've been trying to use Ember Parachute with [email protected] and [email protected] with ES6 classes and decorators. The decorator form does not seem to work and complains about the property being read only.
Controller:
import { action } from '@ember/object';
import { queryParam } from 'ember-parachute/decorators';
export default class FooController extends Controller {
@queryParam({
as: "foo",
serialize(value) {
return value;
},
deserialize(value) {
return value;
}
})
foostate = "my state";
@action
updateState() {
this.foostate = "my new state";
}
}
Template:
{{page-title "Foo"}}
<button {{on "click" (action "updateState")}}>
Update state
</button>
{{outlet}}
When I click the button I am returned the error
at FooController.updateState (foo.js:38)
at Backburner._run (backburner.js:1013)
at Backburner._join (backburner.js:989)
at Backburner.join (backburner.js:760)
at join (index.js:168)
at index.js:770
at instrument (index.js:144)
at index.js:769
at Proxy.<anonymous> (index.js:727)
It doesn't seem to reach the serialize / deserialize methods at all, and fails at the point of trying to update the value.
I have also tried adding @tracked
into the mix, but this still returns the same error. Hopefully I'm doing something wrong, but I can't see where.
Thanks in advance.
Ran into a weird bug when you call replaceRoute and only change query params for the current route inside the setup method. What happens is the setup method runs and the query params are changed. The subsequent call ember parachute makes to queryParamsDidChange seems to contain the original(not updated) values in queryParams
but includes any updated query params in changed
. This cause some weird issues with my logic which was relying on changed
.
Assume we have query params foo
and bar
and they default to empty strings. First hit the route and setup
is called where the queryParams
are { foo: '', bar: '' }
. Then use replaceRoute in setup
and set them to { foo: 'foo', bar: 'bar' }
. When queryParamsDidChange is called its queryParams
will be { foo: '', bar: '' }
. but its changed
will be { foo: 'foo', bar: 'bar' }
. Let me know if you need a full reproduction and I can toss one together.
First off, I think I just stumbled upon a gem. ๐ LOVE the problems this addon is proposing to solve!
(Let me know if my expectations are off on this or not.)
I'm assuming that anywhere/anytime I set setDefaultQueryParamValue
and those queryParams are in the URI they'll be removed (because they are now the default)? Currently that isn't the case though, looks to be the same way in the demo as well. You add "Jump" to the tags
and hit "Set as Defaults" but it remains in the URI.
Is this the expected behavior?
Then, my own application, (perhaps you can tell me if this is the improper place to use setDefaultQueryParamValue
):
Within my route's setupController
I make a request to the API and in that response I'm able to derive what my queryParams defaults will be so I fire controller.setDefaultQueryParamValue('facetContext', record.mapBy('key'));
however like I previously noted the URI does not change and is still populated with the query param values (which should now be the defaults).
Thanks!
EDIT: I've also tried moving my setDefaultQueryParamValue
call into the beforeModel
hook in case things need to be set before a model hook resolves.
Just as a test if I was to statically set the defaultValue: ['value1', 'value2'],
it will work as expected (omitting these values from the URL) but using setDefaultQueryParamValue
instead does not work.
I'm seeing unexpected values of queryParams on a controller using decorators.
Steps to reproduce:
tests/dummy/app/controllers/index.js
.init(){
this._super(...arguments);
console.log(this.get('queryParams'));
}
[
{"parachuteOpen":{"as":"parachute"}},
{"parachuteOpen":{"as":"parachute"},"page":{"as":"page"}},
{"parachuteOpen":{"as":"parachute"},"page":{"as":"page"},"search":{"as":"search"}},
{"parachuteOpen":{"as":"parachute"},"page":{"as":"page"},"search":{"as":"search"},"tags":{"as":"tags"}}
]
I would have expected this value to be in one of the following formats:
[ "parachuteOpen", "page", "search", "tags" ]
{"parachuteOpen":{"as":"parachute"},"page":{"as":"page"},"search":{"as":"search"},"tags":{"as":"tags"}}
I believe this is cause when each decorator adds an additional init call.
One possible solution might be to guard against calling init multiple times.
Would it hurt, if we were able to access the corresponding Controller
from the serialize
and deserialize
methods?
I am asking primarily because I need to synchronously access the store
service, in order to lookup a record for an ID. Basically something like this:
new QueryParams({
someModel: {
defaultValue: null,
serialize(model) {
return model ? get(model, 'id') : '';
},
deserialize(id) {
return id ? get(this, 'store').peekRecord('model-name', id) : null;
}
});
Do you think this is a form of unhealthy entanglement, even though the lookup is guaranteed to work synchronously?
Query parameters are allowed to be repeated in URLs, e.g. status=PaidTrial&status=Paid
. As far as I can tell, ember-parachute doesn't seem to offer a means of accessing these duplicate query parameters. I know it would be a pseudo-breaking change, but it would be great if duplicate query parameters would cause an array to be passed into deserialize rather than just passing in one of the params and ignoring the other.
Using the add-on in an app is producing the below deprecation warning. I believe this deprecation blocks the ability to upgrade to Ember 4.
DEPRECATION: Using `run.schedule` has been deprecated. Instead, import the value directly from @ember/runloop:
import { schedule } from '@ember/runloop';
These usages may be caused by an outdated ember-cli-babel dependency. Usages of the Ember Global may be caused by an outdated ember-cli-babel dependency. The following steps may help:
...
Not sure if there are other instances of deprecated usage, but this particular warning is traced to:
Also noticed this usage:
setup({queryParams})
hook only gets the default values not those set in the current URL. Is there another hook that I'm not aware of?
If I do my fetchData from the setup method, its ignoring values in the URL on page load.
I've just upgraded to 3.6 and found this deprecation: https://www.emberjs.com/deprecations/v3.x/#toc_ember-polyfills-deprecate-merge
I tracked to offending code to
I'm doing query param validation on page load in the setup hook:
setup({ queryParams }) {
if (this.isPastDate(queryParams.date)) {
this.set('date', null);
}
this.fetchData(queryParams);
}
While the 'date'
controller value updates, the URL still has the old value for date
.
Is setup()
hook not ideal for changing query params? Wanted to avoid using beforeModel()
on the route, since this is more concise.
https://github.com/offirgolan/ember-parachute/blob/master/app/services/qp.js#L1
The file cannot be found when injecting the service, i.e.
ember-metal.js:3988 Error: Could not find module `ember-parachute/services/qp` imported from `bwt/services/qp`
at missingModule (loader.js:247)
at findModule (loader.js:258)
at Module.findDeps (loader.js:168)
at findModule (loader.js:262)
at requireModule (loader.js:24)
at Class._extractDefaultExport (index.js:392)
at Class.resolveOther (index.js:113)
at Class.superWrapper [as resolveOther] (ember-utils.js:423)
at Class.resolve (resolver.js:164)
at resolve (container.js:873)
I'd submit a fix if I knew where the service was..
This project is exactly what I'm looking for, but for the life of me I can't figure out how to bind input values to the query parameters. I'd love a look at the parachute demo!
Hello,
I have found this add-on very interesting - great job :) However, I wanted to ask If you are planning any support of ember-fastboot
. Server-side prerendering is a must have for many apps, so giving it up completely is impossible for me.
Non-blocking UI is a good thing, but fetching all data in controller actually makes ember-fastboot
impossible to work (as it renders blank/skeleton page to web crawlers).
What do you think @offirgolan? :)
Using pushObject
to add an element to an Ember.Array-backed QP does not fire the corresponding queryParamsDidChange
hook.
Hello,
I was under the impression that the reload
option was to replace the refreshModel
on the route, but it seems it does not.
It would be nice to actually regroup the route query params options under the same parachute config within the controller: https://emberjs.com/api/ember/2.14/classes/Ember.Route/properties/queryParams?anchor=queryParams
I don't know if it is possible, but it would be incredibly useful for the serialize and deserialize functions to have access to the object the query params are mixed into. For example, consider a query param that represents an array index. The deserialize function should be able to sanity check that index to make sure it's in range.
const myQueryParams = new QueryParams({
foo: {
deserialize(value) {
const length = this.get('bar.length'); // TypeError: this.get is not a function
// ..
}
}
});
export default Ember.Controller.extend(myQueryParams.Mixin, {
bar: []
});
https://github.com/emberjs/rfcs/blob/master/text/0281-es5-getters.md
https://travis-ci.org/offirgolan/ember-parachute/jobs/328966177#L754-L770
Error: Assertion Failed: You attempted to access the
firstObject._getter
property (of QueryParam,QueryParam). Due to certain internal implementation details of Ember, thefirstObject
property previously contained an internal "descriptor" object (a private API), thereforefirstObject._getter
would have beenfunction () { return objectAt(this, 0); }
. This internal implementation detail was never intended to be a public (or even intimate) API.This internal implementation detail has now changed and the (still private) "descriptor" object has been relocated to the object's "meta" (also a private API). Soon, accessing
firstObject
on this object will return the computed value (see RFC #281 for more details).If you are seeing this error, you are likely using an addon that relies on this now-defunct private implementation detail. If you can, find out which addon is doing this from the stack trace below and report this bug to the addon authors. If you feel stuck, the Ember Community Slack (https://ember-community-slackin.herokuapp.com/) may be able to offer some help.
If you are an addon author and need help transitioning your code, please get in touch in the #dev-ember channel in the Ember Community Slack.
at new EmberError (http://localhost:7357/assets/vendor.js:24683:25) at Object.assert (http://localhost:7357/assets/vendor.js:24926:15) at Object.get (http://localhost:7357/assets/vendor.js:34533:42) at objectValues (http://localhost:7357/assets/test-support.js:2822:15) at objectValues (http://localhost:7357/assets/test-support.js:2823:40) at Assert.propEqual (http://localhost:7357/assets/test-support.js:4953:15) at Object.<anonymous> (http://localhost:7357/assets/tests.js:579:12) at runTest (http://localhost:7357/assets/test-support.js:4120:30) at Test.run (http://localhost:7357/assets/test-support.js:4106:6) at http://localhost:7357/assets/test-support.js:4312:12
Hi,
First of all, thanks for creating and maintaining this awesome addon! ๐
It would be awesome if you could provide a way to access the serialized query params from the controller. This way I wouldn't have to serialize them manually when I fetch the data..
I'd be glad to help with this, just let me know if you think it is a good idea.
Observing this error when using the @queryParam
decorator:
Error: Assertion Failed: Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container.
Strangely, it throws the error when trying to set up the service injections on my controller.
Usage:
export default class StuffController extends Controller {
// error occurs when trying to set up this injection
@service('stuff') stuffAPI;
@tracked stuffs = [];
@queryParam({ refresh: true }) page = 1;
@queryParam({ refresh: true }) pageSize = 100;
...
}
Versions
"ember-cli": "~3.13.0",
"ember-parachute": "^1.0.2",
"ember-source": "~3.13.1"
When this addon is used inside of an engine, it's initializer is run twice, once for the parent app and once for the engine. This results in all of the hooks being fired twice.
For example, the queryParamsDidChange
hook will run twice every time a query param changes.
I can create a demo app if you'd like.
Should we be keeping state or QP values?
For example, we want to display a Clear All
button when a query param is not its default value. How do we do that?
Option 1
Pass a new property to queryParamsDidChange
that is an object that contains properties that are not their default values. This is different then #3 which exposed a present
object. Since we allow to update the defaultValue of a param at any time, a param can be present but still be equal to its default value. (Should this replace the present
property?)
Option 2
Keep some sort of state object on the service or on the controller.
// some/file/foo.js
sortHasChanged: computed.readOnly('qp.state.fooIndex.sort.hasChanged'),
qpsHaveChanged: computed.readOnly('qp.state.fooIndex.hasChanged')
IMO I'm a bigger fan of Option 1 since we can explicitly set properties based on the object returned.
As of emberjs/ember.js#16710,
NAME_KEY
is deprecated. I think we just need to override the toString
method on the controller mixin.
When a route has a controllerName defined, and the route doesn't have an explicit controller for itself, lookup-controller util throws an error at this line:
Taking just get(route, 'controller') will remain undefined for the route and it tries to get the default factory.class in the above line, but instead the route has a definition as controllerName as something else.
Instead if it also takes get(route, 'controllerName') in addition to get(route, 'controller'), it seems to solve the problem. But unsure if this is the right approach.
Ember version: 2.4
I would like to be able to define some query parameters dynamically. My first approach is to do this from the Route in setupController
:
setupController(controller, model) {
// Parachute things here, dynamically build QP configuration object
const parachuteController = controller.reopen(ParachuteParams.Mixin);
super.setupController(parachuteController, model);
}
This does not work because the query params don't seem to be set or updated when the properties are changed on the controller.
I've researched this quite a bit, but I can't find any different approach other than this discussion.
Any thoughts appreciated, thanks
import { queryParam, withParachute } from 'ember-parachute/decorators';
export default class ApplicationController extends Controller {
@queryParam
selectedZoning = [];
}
selectedZoning
is undefined when called from my template. No errors. Using Ember 3.10.
Any ideas?
I'm not sure if it was supported properly, but it worked well before upgrade to 0.3.8
We used a service to store query params in application controller to be accessible within our application.
So it was was working code
export const appQueryParams = new QueryParams({
'someService.property': {
as: 'property',
defaultValue: 3600,
replace: true,
deserialize(value) {
return parseInt(value);
}
},
});
export default Controller.extend(appQueryParams.Mixin, {
someService: Ember.inject.service(),
})
But now it works only in case of alias is being set in controller like this
export const appQueryParams = new QueryParams({
someServicePropertyAlias: {
as: 'property',
defaultValue: 3600,
replace: true,
deserialize(value) {
return parseInt(value);
}
},
});
export default Controller.extend(appQueryParams.Mixin, {
someService: Ember.inject.service(),
someServicePropertyAlias: alias('someService.propertyAlias'),
})
Is this functionality supported? Or maybe there are issues in our code?
Thanks for help
What do you think about adding a way to prevent a query param from changing? In a use case where you might bind a tab-like interface to a query param, with the active tab in the URL. With a normal route-driven UI, you could hook into willTransition
to prevent a transition, but there's no way to have similar behavior with Parachute. Supporting refreshModel
would solve this specific use case, but I know that that's not going to be supported.
I'm imagining something like queryParamsWillChange
that could return false
to reject the change
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.