I have the below route structure.
App.Router.map(function() {
this.resource('projects', function() {
this.resource('listings', {path: '/:project_id/listings'}, function() {
this.route('listing', {path: '/:property_code'});
});
});
});
I replicated this structure and created a fiddle.
Fiddle: http://jsfiddle.net/aqHnt/6/
I hope the router is self-explanatory. I have a bunch of projects which each have a bunch of listings and each listing will have some additional details. Because these are nested resources, each child resource renders in to the {{outlet}} of it's parent template.
What I need is to entirely overwrite the parent template and as per a suggestion in a different post, I'm using the resources index route to achieve this.
So If you click on a project, the entire projects template will be replaced with the listings template. It's all good up to this point but I can't seem to achieve the same with listings. When I click on a listing, I want the entire listings template to be replaced by listing details. Can someone point out what am I doing wrong here.
Here is a possible solution: jsfiddle.
You were missing the listings template besides the listings/index one, as well as the route ListingsIndex. This way you replicate the same pattern you use at application level.
You could also consider using renderTemplate to specify in which outlet you need to render a given template.
Hope it helps!
Related
I'm using vue.js to build a PWA. Despite the fact that this isn't a desktop browser app, I'm thinking of ways to better utilise the otherwise wasted real-estate by combining multiple views into a single larger view.
For example, on mobile, there are 2 views with distinct routes - Select Outlet and Order Items. Is there any way to combine both these views only for the desktop with minimal modification? Thank you!
Abstract
I have a proposition of solution. Not sure if it will satisfy you but maybe it will give you a new perspective at least.
Example
Router setup:
const routes = [
{
path: '/combined-components',
name: 'CombinedComponents',
components: {
default: WrapperComponent,
'firs-component': SelectOutlet,
'second-component': OrderItems
},
}]
Template setup:
<div class="wrapper-component">
<div class="container">
<div class="first-component">
<router-view name="first-component"></router-view>
</div>
<div v-if="isMobile" class="second-component">
<router-view name="second-component"></router-view>
</div>
</div>
<div>
Explanation
By using the name attribute for <router-view> we can decide which component will be displayed depending on the current route. So we have one parent component in this case WrapperComponent and inside it's template we can freely place another <router-view> and in routes.js (or just routes const that you pass to configure router) you can specify which component you want to be placed in the slot of first-component and second-component. That allows you to combine 2 of them and just proceed further routes without leaving WrapperComponent. Wha is left is to define if you should display the second component or not. Depending on isMobile that you can define yourself (I would assume based on screen width).
Docs
Read more here: Vue Router Docs
Summary
In this approach, it works from the other side. You prepare it for desktop and just restrict it for mobile.
A question regarding transclude within an angular 1.5.8 component, and it's uses.
Here is an example of some code;
var app = angular.module('app', [])
function AccordionController () {
var self = this;
// add panel
self.addPanel = function(panel) {
// code to add panel
}
self.selectPanel = function() {
//code to select panel
}
}
// register the accordion component
app.component('accordion', {
template: '<!---accordion-template-->',
controller: AccordionController
}
function AccordionPanelController () {
// use parents methods here
var self = this;
// add panel
self.parent.addPanel(self);
// select panel
self.parent.selectPanel(self);
}
// register the accordion-panel component
app.component('accordionPanel', {
// require the parent component
// In this case parent is an instance of accordion component
require: {
'parent': '^accordion',
template: '<!---accrodion-panel-template-->',
controller: AccordionController
}
My question is would it be better to nest all the according panels within the parent using transclude or alternatively pass in a data array to the parent which this loops out the required number of panels based on the array passed inside using a binding.
Thanks
// added
Many thanks for your reply, an example I have of transclude possibly being necessary is in the following bit of code
<modal modal-id="editCompany" title="Edit Company"> <company-form company="$ctrl.company"></company-form> </modal>
Here we have a modal component which may have a variety of other components used within it, on the example above I am adding the company form, but this could we be an contact form. is there an alternative way?
I've worked with angular pretty extensively. Two enterprise tools managing and displaying large amounts of data, dozens of interactive widget modules, all that.
Never, once, have I had anything to do with transclude. At work we are explicitly told not to use it (link functions too). I thought this was a good thing, and the way Angular 2 turned out it seemed that thinking wasn't totally without reason.
I would go with the iteration to lay out the required number of items. At work this wouldn't be a choice because transclude wouldn't be an option.
The thing with using transclude in a component architecture is that it visually breaks the idea of single responsibility and messes with the architecture.
<html>
<navigation></navigation>
<accordion>
<accordion-panel></accordion-panel>
</accordion>
<footer></footer>
</html>
In this example you know your page has a navigation menu, an accordion and a footer. But at the index level (or root component) you don't want to know / see what the accordion contains.
So the accordion-panel component should only appear in its direct parent component.
As for your other question, through the use of require or attributes you pass an array of panels that you iterate using ng-repeat inside the accordion component.
app.component('accordion', {
template: `<accordion-panel ng-repeat="..."></accordion-panel>`,
controller: AccordionController
}
Routing in Ember.js is troubling me, and I can't seem to find the "correct" way of doing what I want to do.
I have a route, let's call it #/map, which contains a series of top-level and containers of child views.
Hierarchically, I have a top map_view, which contains 4 additional views: A topbar (which has topbar menu item triggers within it), a sidebar (which has sidebar menu item triggers in it), and two containerViews (a sidebar menu containerView and a topbar menu containerView), which will contain one or more nested views that are programatically inserted on clicking a menu item trigger.
My issue is that while this works, and I can embed all of these views into their various templates, none of them are linking with controllers, and the controller they are picking up is the map_controller (which makes sense as that is the linked outlet controller for the top level view). Currently I am using a method described on Ember's github here, but it seems a little...hacky?
Here is a JSFiddle showing the problem. Notice that the controller for level-one-entry and level-two-entry is the index_controller: http://jsfiddle.net/fishbowl/Z94ZY/3/
Here are some code snippets for what I am doing to get around it:
map.hbs:
<section id='map'>
{{view App.SidebarView}}
{{view App.TopbarView}}
<div id='map-canvas'></div>
</section>
topbar_view.js:
var TopbarView = Em.View.extend({
templateName: 'topbar',
classNames: ['topbar-container'],
init: function() {
var content = this.get('content'),
controller = App.TopbarController.create({
view: this
});
this.set('controller', controller);
this._super();
}
});
module.exports = TopbarView;
topbar_controller.js
var TopbarController = App.ApplicationController.extend({
content: Ember.computed.alias('view.content'),
trigger: null,
start_date: null,
end_date: null,
travelling: null,
word: 'topbar'
});
module.exports = TopbarController;
I'm not doing anything special in the router other than declaring this.route('map'). A further problem i'm having is that whenever I declare needs: ['some_other_controller'], I get an error
<App.TopbarController:ember413> specifies 'needs', but does not have a container. Please ensure this controller was instantiated with a container.
Am I missing something blindingly obvious about how to go about linking these together. I'm guessing that i'm using routing incorrectly. I don't want to change what the URL is, as i'm technically not moving pages, just opening and closing menus on the page, but I don't really understand how else i'm supposed to use the router to achieve this.
EDIT 2: i've mocked up another jsfiddle of what I could do with outlets and link-to's, but i'm not sure that I want the URL changing (as you'd probably be able to do odd things with the back button etc): jsfiddle - The alternative to this is to set location: 'none' in the Router, but I don't really like that option either...
I try to develop a simple Ember.js app.
I think that these screens describe the desired scenario good enough.
Buttons on the top are #link-tos. Note that I want the first button to be highlighted on the 3rd screen.
It's easy to find examples where the 3rd template lives in the outlet in the 2nd one, but I need some kind of template replacement in the main outlet.
Please help me to achieve this behavior. Hope that my description is clear enough.
You can make list and detail routes same level, so they both are rendered to the same outlet, one at time. Like that:
App.Router.map(function() {
this.resource("movies", function() {
this.route("list");
this.route("view", {path:"view/:movie_id"});
});
});
App.MoviesIndexRoute = Em.Route.extend({
redirect : function() {
this.transitionTo('movies.list');
}
});
All the rest is done as allways
I have a hierarchy of nested routes in my ember app. I want one of the child routes to bypass rendering it's parent template and render directly into the application template. However, I still want to keep the route hierarchy, because I need the models from the parent routes in the child route. What I did is I defined the renderTemplate hook on the child route to render into the application:
renderTemplate: function() {
this.render({ into: "application" });
}
This works, but when I then click on a link to the parent route, nothing is rendered. I put together a small jsfiddle to demonstrate this: http://jsfiddle.net/H7gvz/1/ - run it, then click on one of the names, then click on "Index". I expect the PeopleRoute to render the people template but instead nothing is rendered.
Is this a bug or am I doing it totally wrong? What should be the correct way to do this?
Whenever you use nested routes, transitioning from child route ('people.show') to parent route ('people'), will be redirected to the 'index' route. Rendering your 'people' template in App.PeopleIndexRoute will solve your problem.
App.PeopleIndexRoute = Em.Route.extend({
renderTemplate: function() {
this.render('people',{ into: "application" });
}
});
Your working fiddle