So let's say you would want to create a basic CRUD todo app. I think it shouldn't matter if you are using the Angular, React or Vue routing. You would come up with a router setup like this
/todos => view all todos
/todos/:id => view one todo by id
/todos/:id/edit => edit one todo by id
/todos/new => create a new todo
So as you might have noticed the last route won't work because the new would act as an id.
Quick fix for that:
I could change the order and put the create route before the other two routes relying on the id. But then the user would never be able to call a new todo new if the id is the todo title.
Quick fix for the next one:
I could put something like /view before /:id. The route would look like /todos/view/:id/edit
The word view might be misleading because you want to edit the resource
The user might expect the route to be /todos/:id so /todos/.../:id might lead to a bad user experience
Is there a common approach for this? If putting something between (/todos/.../:id/edit) is the only way, does a common word exist?
Thanks in advance.
One common pattern is to use the edit route for creating a new item using an id of 0. Although changing the order will also work:
/todos
todos/edit/:id
todos/create
todos/:id
Related
So, here is the thing, I'm learning React right now, and I'm building a small taskmanager webapp with React as frontend and Rails(API) as Backend to pratice using React with Rails(which I'm already used to build other webapps with).
The tasks are objects in the database which have a "title" as a string, and "done" as a boolean to indicated if they're done or not.
Using async and await fetch('') I managed to create functions to be able to pass methods directly to the database to check and uncheck the tasks as done, and also delete the tasks. Like that, for example:
async deleteTask(task) {
if (window.confirm(`Are you sure you want to delete: "${task.title}"`)) {
await fetch(`http://localhost:3001/tasks/${task.id}`, {method: 'DELETE'});
this.props.loadTasks();
}
}
Now I want to create a function to delete ALL of the done tasks at once. How would I do that? How do I take all of the tasks and filter them by "done == true" or something like that and pass a DELETE method to the database?
Thanks in advance, any help is appreciated! I tried many alternatives, even tried something like that, no sucess:
async deleteAllDoneTasks() {
if (window.confirm(`Are you sure you want to delete all done tasks?`)) {
await fetch(`http://localhost:3001/tasks/)`, {method: 'DELETE FROM Tasks WHERE done = 1'});
this.props.loadTasks();
}
}
EDIT¹: So, according to JMadelaine this can't be made by the frontend. How do I do that in Rails then? And how do I call that in React, make it happen when I press a button?
I commented below what I would do first. I'd appreciate any insight, help, or solutions. Thanks :)
First of all you need a custom route for this action as it is not default CRUD action.
So in the routes.rb under the tasks route add custom route like:
delete 'tasks', to: 'tasks#multiple_delete'
Then in TasksController define multiple_delete method with code inside which will delete desired tasks and return answer to your client, something like:
def multiple_delete
::Task.where(done: true).destroy_all
head :ok
end
and then in your React, according to answer from server you can do some things.
Then go to your React code, on desired button add onClick event (I do not know which framework you use, I will share example of Shopify code which I am familiar with.
outside the render() do:
deleteAllDoneTasks = () => {
if (window.confirm(`Are you sure you want to delete all done tasks?`)) {
await fetch(`http://localhost:3001/tasks)`, {method: 'DELETE'})
}
}
inside the render() do:
<Button onClick={this.deleteAllDoneTasks}>
Updated: 11:36PST 07 Dec 2017
All I'm trying to do is create an array containing a list of current ID's in the model to use in a child component, but somehow seem to be missing something obvious. If it is relevant, I am using Ember 2.17.0 with Ember Data 2.17.0 as well.
The route returns an array of models very similar to a findAll, but modified to work with a REST endpoint I do not have any control over. I need an array of the id's from the model to use in a component embedded in the route. Based on feedback, I have attempted to implement this in both the route and the controller.
In the controller, I'm trying it this way.
searchIdArrayC: computed('model', () => {
return this.get('model').map((record) => record.get('reachId'));
})
..and in the route I'm trying it this way.
searchIdArrayR: computed('model', () => {
return this.modelFor('reaches').map((record) => record.get('reachId'));
});
When I look at it in the Chrome Ember Inspector, for both the route and controller it is telling me Error while computing: searchIdArrayR or Error while computing: searchIdArrayC.
Just to try and do some testing, I sent both the route and the controller to the console. With both the route and controller, the aforementioned methods are working, so I am really confused.
Thank you in advance for any help or guidance you may be able to offer.
In route file, model is a function, but you are treating it like model property which is available in the corresponding controller.
If you can move searchIdArray computed property to corresponding controller then that should work.
Let's say I have a component that creates or edits a thing.
The url for the creation is /things/create and the url for edition is /things/edit/4. These routes have the same parent.
Once I fill in the form, I call some webservice and then I go back to my previous state which was /things.
How do I tell angular to go back to the parent route?
I could use this.router.navigate(['../'], {relativeTo : this.route}); but ['../'] would only work for /things/create. For /things/edit/4 it would go back to /thing/edit which doesn't exist.
This component is used in two different places, one of which has an extra step before the creation so I can't use back().
Logic based on the current url
if(router.url.indexOf('create')>= 0){
this.router.navigate(['../'], {relativeTo : this.route});
}else {
this.router.navigate(['../../'], {relativeTo : this.route});
}
so if your current URL path contains the create you know you just have to go back one level, otherwise you go back two levels for the edit.
Use Input to get base URL
Another approach might be to have an #Input for the base URL to go back to. So each component that initializes your component has to pass it the parent url.
{
#Input
parentUrl;
this.router.navigate[parentUrl];
}
You can use
this.router.navigate['/things']
So you should be able to check for the id of the thing in the ActivatedRoute params to get the context if the component is creating or editing a component. If there is a param['thingId'] then go to ../../ otherwise go to ../
May be this idea a bit old school but I am sure it will work and is quite simplistic to implement. You can add query param called 'source' and navigate to 'source once the operation is done.
So I'm working on building a dynamic model for a project that reacts to data sent from an API. The api will return, among other things, what your location should be and this in turn becomes the url. So, eg:
{
location: 'xyz'
(...)
}
So currently my router will transition to the right route dynamically. But I still have to hardcode each route ( IndexRoute, LocationXYZRoute, LocationABCRoute, etc).
My goal is to create a single route that handles things dynamically. We'll call it App.LocationRoute and my routes would look something like:
App.Router.map(function() {
this.resource(':location', function() {
this.route(':subLocation')
}
}
Now, I have two architectural questions:
1) Whats a good way to handle this sort of dynamic routing? (I've read through the guide about dynamic routing using the ':post_id' type example, but I think I need a more holistic example to really grasp it.
2) The API sends back a whole host of other data as well. I want to add this to the route's model but I also have some other static models. Doing...
this.controllerFor(location).set('content', APIdata);
... works, but it does not set for routes currently using static models. I tried something like:
this.controllerFor(location).set('apiData', APIdata);
and...
this.controllerFor(location).set('model:apiData', APIdata);
... but neither worked.
Any suggestions?
1) Yes, you should use dynamic segment
this.resource('location', { path: '/location/:location_id' }, function() {
this.resource('sublocation', { path: '/sublocation/:location_id' });
});
2) Are you using ember-data? You could check sideloaded data. Anyway, you could read the json and set the payload of each entity for each specific route.
this.controllerFor('location').set('content', APIdata.location);
this.controllerFor('user').set('content', APIdata.user);
People could help you better, if you separate your questions and create a http://emberjs.jsbin.com/ with isolated each specific case?
The typical route in Durandal looks like:
Regular - http://mysite.com/#/Home
Id - http://mysite.com/#/Person/123 (Person/:id)
I'm trying to figure out which method(s) I need on http://durandaljs.com/documentation/Router/ I need to overwrite to support something like this:
http://mysite.com/#/Abc123/Home (:siteId/Home)
http://mysite.com/#/Abc123/Person/123 (:siteId/Person/:id)
How would I implement something like this?
You answered your own question. To implement http://mysite.com/#/abc123/Home you have to define a route that models that, for example:
var router = require('durandal/plugins/router');
router.mapRoute('#/:sideId/home','viewmodels/customViewModel','This is the title of the view');
when someone goes to your route, it will navigate to your customViewModel.
Just remember, that the router will navigate to the easiest route first, so order them correctly (for example, if you have router.mapRoute('','viewmodels/home','home view') as your first route, the router will always go to this route, and not read look further in its router queue).