Angular Router pass data to component - javascript

Is it a good practice to pass data with the angular router to a component or should i use an service instead?
At the moment the component gets the data like this:
this.account = activatedRoute.snapshot.data.account

There are several ways to pass data to an angular component.
For objects like user account, I would use a provider (to have it ready on component init), a service (for sharing around app) or a guard (e.g. if you want to navigate out when not logged in).
When I want to reuse the same component in different routes and give it some hints about is behavior, I would use router data.
Another use case I met is to define a global app state using the activated route(s). Each route may define its data, a service listen for router events and stores the merged state.
It helps me with large apps to have a route-based configuration for title, metas, toolbar and menus visibility, etc...

If you want to pass data through a route, here is a simple example.
Make your route to look like this:
{ path: 'todo', component: TodoComponent, data: { id:'1', name:"Todo Title"} }
Then in your Component you can do something like this:
ngOnInit() {
this.activatedroute.data.subscribe(data => {
this.todo = data;
})
}
Was this helpful?

Related

In EmberJS how can you use transition data in a controller?

I am getting the transition data in the route js file like so:
beforeModel(transition) { console.log(transition) }
And I want to use it in a function in my controller like this:
import Controller from '#ember/controller';
export default class ListingsController extends Controller {
get pageTitle() {
if (this.transition.targetName == 'foo') {
return 'page title';
}
}
}
And then I want to display the result like this:
<h1>{{this.pageTitle}}</h1>
I cannot find a way to pass the transition data from the route to the controller. Any ideas?
While you technically can leverage the beforeModel to get the controller via this.controllerFor as #KathirMagaesh suggests, I wouldn't actually advocate for this solution. It's definitely not the normal or expected Ember pattern. Furthermore, if you look at the transition api, there is no reference to transition.targetName. If this works, this is private api and thus brittle.
If you need to change a property based on the current route, you should be using the public router service which provides some useful properties for this very purpose!
For example, in your controller you could have a computed property that leverages the router service to determine what the page title should be
import Controller from '#ember/controller';
import { computed } from '#ember/object';
import { inject } from '#ember/service';
// this injects the router service into our component via Ember's DI framework
router: inject(),
export default Controller.extend({
pageTitle: computed('router.currentRouteName', function(){
let currentRoute = this.router.currentRouteName;
if(currentRoute === 'foo'){
return 'page title';
}
// do other stuff for other routes.
})
})
This leverages currentRouteName which is the period separated name like foo.bar. You can also also access the url via currentURL which would be /foo/bar
PS. Since I haven't used ES6 classes yet, I've provided the old style ember solution. You'll probably need to use the #computed decorator or #tracked where I'm using the computed function. I only know about the Octane ember style from RFCs and awesome blog posts but am not up to date with what's landed.
PPS. If you're on old ember, the current route name / URL properties are available on the application controller.
In the beforeModel hook use
this.controllerFor(currentrRouteName).set('transition', transition);
This will set transition property in controller of the current router.
For more on controllerFor()

Pass Laravel data to Vue component

I'm creating a single page application (SPA) that uses Vue Router, therefore it is comprised mostly of Vue components with one blade component that puts it all together using
<router-view></router-view>
I want to know how I can pass data computed within my controller and pass it to a Vue component. The current way I'm doing it is by exposing extra API endpoints, for example in my controller I have:
public function countUsers()
{
$userCount = DB::table('users')->count();
return $userCount;
}
Then in api.php:
Route::get('usercount', 'UserMController#countUsers');
this way I can get the data within my Vue component using axios.get call to usercount.
Is there a better way of doing this? The data seems to take 1-2 seconds to display on the page and I can't imagine having this implementation for over 20 computations I need to do.
I've seen another method where you attach the data into the JavaScript context using the blade template, but I'm not sure how to get that to work for a SPA with Vue Routers.
get userCount in your controller and pass it to normal blade file. You can pass the variable in vue like below.
<router-view userCount="{{userCount}}"></router-view>
then for accessing userCount variable in vue, you can load this variable from props.
export default {
props: ['userCount'],
name: 'router-view',
},
mounted:function(){
let a = this;
this.userCount = JSON.parse(this.userCount)
}
for more information you should read the documentation first. It will help you understand thoroughly.
https://v2.vuejs.org/v2/guide/components-props.html

Angular detect leaving a route.

I'm using Angular 1.5 and ui-router. I want to detect when a user leaves a route. I've currently got something like:
$scope.$on("$stateChangeSuccess", function () {
if (!$scope.flag) {
//...
$scope.do_work(reason);
}
});
this doesn't quite work because when the user navigates to the this route, $scope.flag is set to false and this function incorrectly fires. Is there an idiomatic way to fire a function when a user navigates away from a particular route, but not when they navigate to it?
I'd say use onExit hook of ui-router which you can specify on single state. But you can't access $scope inside it.
To deal with it, I'd say maintain service which will have shareable data. Change that shareable data from onExit hook of your desired state. Then you can access the same service inside your controller as well.
$stateProvider.state("contacts", {
template: '<h1>Dummy Template</h1>',
controller: 'myCotroller',
onExit: function(sharableService){
//... do something sharableService variable...
}
})

Passing unsaved record to Ember.js route

Inside an application we allow users to create new records, related to an existing record. To achieve this, we use actions something like this:
createUser() {
var route = this;
var model = this.store.createRecord('user', {
client: route.modelFor('client'),
});
route.transitionTo('user.update', model);
},
The user.update route renders a user-form component, using the model that was passed in the transition. The same route is also used to update existing users.
The issue with this approach is as follows; when refreshing the page, the page errors because the route fails to find the respective record when querying the store (at this point, the URL is /users/null/update). Ideally I'd pass the client (or client.id) argument in the URL so that:
The page can be reloaded without issue.
The client associated with the user is set correctly.
How can I achieve this in Ember.js? I know that this can easily be done using nested routes (by nesting the user.update route inside a client route), but this doesn't make sense visually.
The relevant parts of the router are as follows:
this.route('clients');
this.route('client', {path: 'clients/:id'}, function() {
this.route('users');
});
this.route('user', {path: 'users/:id'}, function() {
this.route('update');
});
All I do in the user/update.hbs template is {{user-form user=model}}
The problem is that the model you just created has no id at that point because it is not saved, ember can´t route to a model without an id, if possible save the model before you try to transition to the route, if you don´t want to save the model because the user can cancel the action check this thread where a user had the same problem (if I understand you problem correctly), I provided a solution for that problem that I´m using in my own project
https://stackoverflow.com/a/33107273/2214998

EmberJS: How to transition to a router from a controller's action

I have an action:
{{action create target="controller"}}
which I have targeted to the bound controller (rather than the router) like this:
App.AddBoardController = Ember.Controller.extend
create: ->
App.store.createRecord App.Board, {title: #get "boardName"}
App.store.commit()
//TODO: Redirect to route
How do I redirect back to a route from the controller action?
Use transitionToRoute('route') to redirect inside an Ember controller action:
App.AddBoardController = Ember.Controller.extend({
create: function(){
...
//TODO: Redirect to route
this.transitionToRoute('route_name');
}
...
In fact, this is not Ember idiomatic. From what I know, and what I have learnt from Tom Dale himself, here are some remarks about that code:
First, you should not transitionTo from elsewhere than inside the router: by doing so, you are exposing yourself to serious issues as you don't know in which state is the router, so to keep stuff running, you will quickly have to degrade your design, and by the way the overall quality of you code, and finally the stability of your app,
Second, the action content you are showing should be located inside the router to avoid undesired context execution. The router is indeed a way to enforce a coherent behavior for the whole app, with actions being processed only in certain states. While you are putting the actions implementation into Controllers, those actions can be called at anytime, any including wrong...
Finally, Ember's controllers are not aimed to contain behavior as they rather are value-added wrappers, holding mainly computed properties. If you nevertheless want to factorize primitives, maybe the model can be a good place, or a third party context, but certainly not the Controller.
You should definitely put the action inside the router, and transitionTo accordingly.
Hope this will help.
UPDATE
First example (close to your sample)
In the appropriated route:
saveAndReturnSomewhere: function (router, event) {
var store = router.get('store'),
boardName = event.context; // you pass the (data|data container) here. In the view: {{action saveAndReturnSomewhere context="..."}}
store.createRecord(App.Board, {
title: boardName
});
store.commit();
router.transitionTo('somewhere');
}
Refactored example
I would recommend having the following routes:
show: displays an existing item,
edit: proposes to input item's fields
Into the enclosing route, following event handlers:
createItem: create a new record and transitionTo edit route, e.g
editItem: transitionTo edit route
Into the edit route, following event handlers:
saveItem: which will commit store and transitionTo show route, e.g
EDIT: Keep reading, Mike's answer discusses some of the problems with this approach.
You can just call transitionTo directly on the router. If you are using defaults this looks like App.router.transitionTo('route', context).

Categories

Resources