Angular2 dynamic templating - templates

How do I use nested templates in angular2. So basically I have a base component and it's childs
- entry.component.ts
- entry.component.html
- navigation
-- sidenav.ts
-- sidenav.html
-route1
--route1.ts
--route1.html
entry.component.html should be a skeleton and the content should be generated dynamically on route changes.
Is it possible to achieve this?

Use templates with child routes.
I separate mine in public and secure routing everything through the layout then loading the routes for which ever layout is chosen.
Make sure to export the child routes and that the correct routes are called in the layout route. Also make sure you use redirectTo in each child routes file.
app.routing.ts
const APP_ROUTES: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full', },
{ path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
{ path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];
Then I have a layouts folder
layouts
layouts/public/public.components.ts
layouts/public/public.components.html
layouts/secure/secure.components.ts
layouts/secure/secure.components.html
child routes
/public/piublic.routes.ts
export const PUBLIC_ROUTES: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'p404', component: p404Component },
{ path: 'e500', component: e500Component },
{ path: 'login', component: LoginComponent },
{ path: 'register', component: RegisterComponent },
{ path: 'home', component: HomeComponent }
];
/secure/secure.routes.ts
export const SECURE_ROUTES: Routes = [
{ path: '', redirectTo: 'overview', pathMatch: 'full' },
{ path: 'items', component: ItemsComponent },
{ path: 'overview', component: OverviewComponent },
{ path: 'profile', component: ProfileComponent },
{ path: 'reports', component: ReportsComponent }
];
Creating components to load into the template
import { Component, OnInit } from '#angular/core';
#Component({
templateUrl: './benefits.component.html',
})
export class BenefitsComponent {
constructor() { }
}
The create its html template,
/public/benefits.component.html'
Now that it is part of the public route. When someone goes to a public route it will be loaded in the chile routes. so inside your
/public/public.routes.ts file you would add it for every new route you wanted to create to load your new html page.

Related

Vue router permission based on User Role from Django Rest Framework

I have Django and Vue project and I need to add permissions in the Vue router based on user role.
I managed to do this in the template by accessing the user data from my user API.
<li class="nav-item active mx-1 mb-1">
<router-link
v-if="user_data.role != 2"
:to="{ name: 'activities' }"
class="btn btn-sm btn-success"
>Activities
</router-link>
</li>
<script>
import { apiService } from "#/common/api.service.js";
export default {
name: "NavbarComponent",
data() {
return {
user_data: {},
}
},
methods: {
setRequestUser() {
this.requestUser = window.localStorage.getItem("username");
},
getUserData() {
// get the details of a question instance from the REST API and call setPageTitle
let endpoint = `/api/user/`;
apiService(endpoint)
.then(data => {
this.user_data = data;
})
},
},
computed: {
isQuestionAuthor() {
return this.requestUser === 'admin_user';
},
isUser() {
return this.requestUser;
},
},
created() {
this.setRequestUser()
this.getUserData()
}
};
</script>
The user doesn't see the button but can still access the pages if enter the path directly in URL.
I can't find a workaround to get the same user data from user API and use it to manage route permissions based on user.role
My router.js looks like this:
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "home",
component: Home
},
{
path: "/activities",
name: "activities",
component: Activities
},
{
path: "/add-activity/:slug?",
name: "activity-editor",
component: ActivityEditor,
props: true
},
{
path: "/activities/:slug",
name: "activity",
component: Activity,
props: true
},
{
path: "/cto-entries",
name: "cto-entries",
component: CTOEntries,
},
{
path: "/add-cto-entry/:slug?",
name: "cto-editor",
component: CTOeditor,
props: true
},
{
path: "/question/:slug",
name: "question",
component: Question,
props: true
},
{
path: "/ask/:slug?",
name: "question-editor",
component: QuestionEditor,
props: true
},
{
path: "/answer/:id",
name: "answer-editor",
component: AnswerEditor,
props: true
},
{
path: "*",
name: "page-not-found",
component: NotFound
}
];
const router = new VueRouter({
mode: "history",
//base: process.env.BASE_URL,
routes
});
export default router;
Is there any way to do this in vue router or there is a better way?
I am new to Vue.js, please help :)
Solved this by using beforeEnter and fetching user role from API...
import { apiService } from "#/common/api.service.js";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "home",
component: Home
},
{
path: "/activities",
name: "activities",
component: Activities,
beforeEnter(to,from,next) {
var user_data = {};
let endpoint = `/api/user/`;
apiService(endpoint)
.then(data => {
user_data = data;
if(user_data.role!=2){
next();
} else {
next("/");
}
});
},
},

Karma Unit Test case coverage for lazy loading in Angular 8

How to write the unit test cases for lazy loading in angular 8. i tried a lot but my unit test cases are not covering "loadChildren" routing.
import { Routes, RouterModule } from "#angular/router";
import { AppRoutingComponent } from "./app-routing.component";
const appRoutes: Routes = [
{ path: "index.html", component: AppRoutingComponent },
{ path: "product", loadChildren: () => import('app/dashboard/product.module').then(m => m.ProductModule) },
{ path: "", redirectTo: "/main", pathMatch: "full" } ];
export const routedComponents = [ AppRoutingComponent,
];
#NgModule({
imports: [routing],
exports: [RouterModule]
})
export class AppRoutingModule { }
Please provide some guidance.
Thanks in advance.

Accessing model properties in Controller - Ember

So, I'm trying to access my model properties in controller.
Controller:
dashobards: [
{ id: 12, name: 'test' },
{ id: 17, name: 'test2' },
];
In route I have model named dashboards
return Ember.RSVP.hash({
dashboards: this.store.findAll('dashboard'),
}).then((hash) => {
return Ember.RSVP.hash({
dashboards: hash.dashboards
});
}, self);
I wanna have result in controller like this:
dashboards: [
{ id: 12, name: 'test' },
{ id: 17, name: 'test2' },
{ id: 17, name: 'test1' },
{ id: 20, name: 'test20' },
];
In controller I am trying to access this model like this:
this.dashborads = this.get(model.dashobards)
And it's not working, is there any other way of doing that?
Another update How to access complex object which we get it from server in ember data model attibute,
Created twiddle to demonstrate
define attribute with DS.attr(),
export default Model.extend({
permissions:DS.attr()
});
route file,
model(){
return this.store.findAll('dashboard');
}
Your server response should be like,
data: [{
type: 'dashboard',
id: 1,
attributes: {
permissions: {'name':'role1','desc':'description'}
}
}]
hbs file,
{{#each model as |row| }}
Name: {{row.permissions.name}} <br/>
Desc: {{row.permissions.desc}} <br />
{{/each}}
Update:
Still I am not sure about the requirement, Your twiddle should be minimalized working twiddle for better understanding..anyway I will provide my observation,
1.
model(params) {
this.set('id', params.userID);
const self = this;
return Ember.RSVP.hash({
dashboards: this.store.findAll('dashboard'),
user: this.store.findRecord('user', params.userID)
}).then((hash) => {
return Ember.RSVP.hash({
user: hash.user,
dashboards: hash.dashboards
});
}, self);
}
The above code can be simply written like
model(params) {
this.set('id', params.userID);
return Ember.RSVP.hash({
dashboards: this.store.findAll('dashboard'),
user: this.store.findRecord('user', params.userID)
});
}
Its good to always initialize array properties inside init method. refer https://guides.emberjs.com/v2.13.0/object-model/classes-and-instances/
For removing entry from array,
this.dashboard.pushObject({ 'identifier': '', 'role': '' }); try this this.get('dashboard').pushObject({ 'identifier': '', 'role': '' });.
if possible instead of plain object you can use Ember.Object like
this.get('dashboard').pushObject(Ember.Object.create({ 'identifier': '', 'role': '' }));
For removing entry.
removeDashboard(i) {
let dashboard = Ember.get(this, 'dashboard');
Ember.set(this, 'dashboard', dashboard.removeObject(dashboard[i]));
}
The above code can be written like, since i is an index
removeDashboard(i) {
this.get('dashboard').removeAt(i)
}
Just do return this.store.findAll('dashboard'); in route model hook, and dont override setupController hook, then in hbs you should be able to access model that will represent RecordArray. you can have a look at this answer for how to work with this.

How to use one template in multiple Ironrouter route?

I want to display the template named "home" with the route "/" and "/home" but with my code it doesn't work
/** Iron router config file **/
Router.configure({
layoutTemplate: 'layout',
notFoundTemplate: '404',
loadingTemplate: 'loading',
fastRender: true,
});
// Home
Router.route('/', {
name: 'home',
waitOn: function() {
return [
Meteor.subscribe('infosContainers'),
Meteor.subscribe('infosMachines'),
Meteor.subscribe('alertes'),
];
},
fastRender: true,
});
Router.route('/home', {
name: 'home',
waitOn: function() {
return [
Meteor.subscribe('infosContainers'),
Meteor.subscribe('infosMachines'),
Meteor.subscribe('alertes'),
];
},
fastRender: true,
});
It doesn't like the fact that the template "home" is in 2 routes (because if I set name: sokasok in the second one it works )
Could you help me ?
'name' is not for the template render, it's the name of the route. What you need to do is call this.render('home') in action of the route.
Router.route('/home', {
waitOn: function() {
return [
Meteor.subscribe('infosContainers'),
Meteor.subscribe('infosMachines'),
Meteor.subscribe('alertes'),
];
},
action: function(){
this.render('home');
}
fastRender: true,
});

Ember-data keeps saying "no mdel was found for"

I am trying to write a EMberjs application, using Ember-Data. also, require.js and coffeescript. despite following each and every guide and discussion I could find, i am still getting 'no model was found for' error.
here are my classes:
main.coffee (entry point for require.js):
require.config
paths:
jQuery: "../javascript/jquery-2.1.1.min"
handlebars: "../javascript/handlebars-v1.3.0"
ember: "../javascript/ember.prod"
ember_data: "../javascript/ember-data.prod",
shim:
ember:
deps: ["jQuery", "handlebars"]
exports: "Ember"
'ember_data':
deps:[ 'ember'],
exports:'DS'
require ["app", "router"], (app, Router) ->
app.deferReadiness()
Router()
app.advanceReadiness()
return
app.coffee:
define "app", ["ember", "ember_data"], (Ember) ->
window.app = Ember.Application.create()
app.ApplicationAdapter = DS.FixtureAdapter.extend()
app
router.coffee:
define "router", ["app", "ember-data", "ember", "models/person"], (app) ->
->
app.Router.map ->
#route 'home', path: "/"
#resource('person', { path: 'person'}, ->
#route('details', { path: ':slug' })
return
)
return
app.HomeRoute = Ember.Route.extend
model: ->
app.PersonRoute = Ember.Route.extend
model: () ->
return #store.find("Person")
models/person.coffee:
class app.Person extends DS.model
first: DS.attr("string")
app.Person.FIXTURES = { person: [
{
id: 1,
first: "first_1"
},
{
id: 2,
first: "first_2"
}
]}
but when i go to http://localhost:9000/#/person, i get this:
Error while processing route: person.index" "No model was found for 'Person'" "EmberError#http://localhost:9000/assets/javascript/ember.prod.js:13949:17
Store<.modelFor#http://localhost:9000/assets/javascript/ember-data.prod.js:11264:1
Store<.findAll#http://localhost:9000/assets/javascript/ember-data.prod.js:10845:20
Store<.find#http://localhost:9000/assets/javascript/ember-data.prod.js:10476:1
app.PersonRoute<.model#http://localhost:9000/assets/javascript/router.js:24:16
apply#http://localhost:9000/assets/javascript/ember.prod.js:19296:1
superWrapper#http://localhost:9000/assets/javascript/ember.prod.js:18867:15
Route<.deserialize#http://localhost:9000/assets/javascript/ember.prod.js:24467:16
applyHook#http://localhost:9000/assets/javascript/ember.prod.js:45215:16
HandlerInfo.prototype.runSharedModelHook#http://localhost:9000/assets/javascript/ember.prod.js:43237:22
UnresolvedHandlerInfoByParam<.getModel#http://localhost:9000/assets/javascript/ember.prod.js:43463:16
bind/<#http://localhost:9000/assets/javascript/ember.prod.js:45089:16
tryCatch#http://localhost:9000/assets/javascript/ember.prod.js:45538:16
invokeCallback#http://localhost:9000/assets/javascript/ember.prod.js:45550:17
publish#http://localhost:9000/assets/javascript/ember.prod.js:45521:11
#http://localhost:9000/assets/javascript/ember.prod.js:28956:9
DeferredActionQueues.prototype.invoke#http://localhost:9000/assets/javascript/ember.prod.js:679:11
DeferredActionQueues.prototype.flush#http://localhost:9000/assets/javascript/ember.prod.js:749:15
Backburner.prototype.end#http://localhost:9000/assets/javascript/ember.prod.js:135:11
createAutorun/backburner._autorun<#http://localhost:9000/assets/javascript/ember.prod.js:521:9
" ember.prod.js:15069
any idea anyone?
EDIT:
it seems like if I move the person.coffee file from /models to the same level as main and App, and change the 'define' line in the router accordingly, it works as expected. Still a mystery to me :(
I'm not 100% sure, but the problem might be in wrong formatted fixtures for App.Person.
Could you rewrite fixtures like this?
app.Person.FIXTURES = [
{
id: 1,
first: "first_1"
},
{
id: 2,
first: "first_2"
}
]
You should be defining your fixtures using reopenClass, so along these lines:
App.Documenter.reopenClass({
FIXTURES: [
{ id: 1, firstName: 'Trek', lastName: 'Glowacki' },
{ id: 2, firstName: 'Tom' , lastName: 'Dale' }
]
});
as seen in the example here http://emberjs.com/guides/models/the-fixture-adapter/
The approach you're using is out of date.