Ember nested route template with conditional HTML in place of outlet - javascript

I have a nested route that looks like:
/products
/products/:productId
And the /products template renders with a sidebar listing all the products, and a "main" content <div> in the center that is populated with a specific product when clicked. ie:
<div id="productsSidebar">
... navigation tree ...
</div>
<div id="mainContainer">
{{outlet}}
</div>
However, I would like for the {{outlet}} to be replaced with a message like
Please select a product to the left.
When there is no child route, ie. we're just looking at /products and the main <div> is otherwise completely empty.
I haven't found any reference/tutorial demonstrating if this is possible - is there a standard way to render a "default" block of HTML if there no outlet available?

You can use the products index route template to display that html text. You may need to generate the route with something like ember g route products/index

Related

Angular - Adding components dynamically in different parent elements

I want to build a multi-step form, where each step is its own tab and the user can go forward/backwards through the form. Each tab has a header, content and navigation buttons.
In my form component, I have an array of all components (each represents a step in the form) and I want to loop through it in the form's template, so that each step has the same structure and if I want to change that structure I should only change the code in the loop, as it's the same for all steps.
This is the array in the form.component.ts:
steps = [
LanguageComponent,
CodeComponent,
HardwareComponent,
SubmissionComponent
]
Or should it be:
steps = [
new LanguageComponent,
new CodeComponent,
new HardwareComponent,
new SubmissionComponent
]
?
This is the pseudo form.component.html:
<div id="tabs">
<div class="tab" *ngFor="let step of steps" id="{{step.header}}">
{{ step.header }}
<app-step></app-step>
{{ buttons }}
</div>
</div>
Each step component has header property.
That way, in order to change the structure of the tab, I only have to change it here once, if the header and buttons go inside each components' template, then I will have to change each component's template, if I want to change the tab structure.
How would you do this, is there a better way to achieve this structure?
Thank you!
You need a placeholder component that houses the form tab structure. Then like you said you only have 1 place that you would have to change the layout.
AppFormTabComponent.html
<ngb-tabset>
<ngb-tab>
<ngbTemplate>
<language-component [form]="form"></language-component>
</ngbTemplate>
</ngb-tab>
<ngb-tab>
<ngbTemplate>
<code-component [form]="form"></code-component>
</ngbTemplate>
</ngb-tab>
...
</ngb-tabset>
Then you would only call your AppFormTabComponent once to use it
form.component.html
<app-form-tab-component [form]="form"></app-form-tab-component>
And your form would be in the app.component.ts page and you would pass the form in to each one of your templates.

Include component from parent app in component contained in node_modules directory

I am working on Vue app that incorporates Vue Bootstrap Calendar, and I would like to be able to override the content of the day cell (handled by the Day.vue component) to add my own custom content inside. My thought was initially to modify the Day component to include <slot></slot> tags and pass in the custom content that way.
The problem has to do with accessing the Day component. To include the calendar in your app, you include the Calendar.vue component, which includes Week.vue, which in turn includes Day.vue. As I understand slots, I have to have the child component (Day.vue in this case) included in the component where I'm passing the data, which means it would need to be included in my own component.
If this is not possible, my other thought is to perhaps modify the library by adding another configuration prop (something like dayCustomContent) to the Calendar.vue that indicates that the Day cell content is custom content, pass that in to Calendar.vue, and then down to Day.vue, and then in the Day.vue template, have a v-if conditional based on this prop that either displays the custom content or the default cell content, something like:
<template>
<div class="day-cell" v-if="dayCustomContent">
...my custom content here...
</div>
<div class="day-cell" v-else>
...default events from my.events goes here...
</div>
</template>
I would probably then need to define a custom component to render whatever custom content I want to display, and somehow include that component within Day.vue.
So to sum up, my questions are these:
1) Is there a way to do what I need with slots?
2) For my second option, am I going down the right path? I'm open to suggestions.
UPDATE: I was able to get this done by adding a boolean customDayContent prop in Calendar.vue like so and passing it down to Week.vue and then to Day.vue:
<template>
...
<div class="dates" ref="dates">
<Week
v-for="(week, index) in Weeks"
:firstDay="firstDay"
:key="week + index"
:week="week"
:canAddEvent="canAddEvent"
:canDeleteEvent="canDeleteEvent"
:customDayContent="customDayContent"
:displayWeekNumber="displayWeekNumber"
#eventAdded="eventAdded"
#eventDeleted="eventDeleted"
></Week>
</div>
...
</template>
<script>
export default {
...
props: {
...
customDayContent: {
type: Boolean,
default: false
}
},
}
</script>
and then in Day.vue, do like I had suggested with v-if:
<template>
<div class="day-cell" v-if="customDayContent">
<custom-day></custom-day>
</div>
<div
class="day-cell"
:class="{'today' : day.isToday, 'current-month' : day.isCurrentMonth, 'weekend': day.isWeekEnd, 'selected-day':isDaySelected}"
#click="showDayOptions"
v-else
>
... existing code goes here...
</div>
</template>
The last part is referencing the CustomDay.vue component referenced in my v-if block. I want the user to be able to define the content of their own custom CustomDay.vue template in their own parent app. However, I'm having trouble trying to figure out how to do that. Following the pattern of including components already in this component, I added this in the components section of Day.vue:
CustomDay: require("../../../../src/Components/CustomDay.vue").default
? require("../../../../src/Components/CustomDay.vue").default
: require("../../../../src/Components/CustomDay.vue")
However, no matter what I try along these lines, I get an error that the relative module was not found. On top of that, I need to add it to the componentsarray only if customDayContent is true. What is the best way to do that? In a watcher or computer property, perhaps? Or another way?

Multiple layouts with Angular

I am building an Angular app and hitting a bit of a snag in how to handle the home page. The home page is 90% different - only the header stays the same - in there I have directives that show user login state for ex.
To make use of routing/templates etc I'd ideally like to have my ngview in the white area of sample shown - that all works fine - just not sure how to build the home page. It doesn't need an ngview area persay since it's the only one of it's kind. I don't want to make it as a second apps however as that seems wasteful and would reload everything.
Googling this brings up suggestions of replacing the white area with a directive but then I think I would lose the whole routing/template benefit.
Alternatives I have seen have code to determine if on home and load a body CSS class etc but that is not ideal either as the content is so different.
UI Router is a possibility but I'd like to avoid prebeta stuff if possible.
Suggestions?
You could have this:
index.html:
<body>
...header..
<div ng-if="isHomePage()">
<div ui-view></div>
</div>
<div ng-if="!isHomePage()">
<div ng-include="'shell.html'"></div>
</div>
...footer..
</body>
home.html (with route '/')
...your home page html...
shell.html (any route different than '/')
<div>
<div>
<div ui-view></div>
</div>
<aside><aside>
</div>
finally, add isHomePage() to your root scope
$rootScope.isHomePage = function() {
return $location.path() == '/';
};

Ember JS Index routes

Can someone better explain with is going on with the implied index route and controllers in Ember JS?
See this example, why is the behavior different in these two examples?
Index route explicitly defined
http://jsbin.com/ILAP/1/
The index route is implied
http://jsbin.com/ILAP/2/
What is confusing to me is why the nesting behavior works in the second example but not the first.
This is the students/student route structure:
students
----index
----student
--------index
First case
Index route explicitly defined
Templates:
<script type="text/x-handlebars" data-template-name="students">
{{ outlet }}
</script>
<script type="text/x-handlebars" data-template-name="students/index">
... omitted ...
<div class="well">
Expecting to render student template here:
<br />
{{ outlet }}
</div>
</script>
<script type="text/x-handlebars" data-template-name="student">
<h2>Student</h2>
<h3>{{name}}</h3>
<h4>{{grade}}</h4>
<h4>{{gpa}}</h4>
</script>
When you make a transition to student.index, first is appended the student template and after student/index. Because you dont have override the default conventions, via renderTemplate. The place where the template is rendered, is into the main outlet (an outlet without name) aka {{outlet}}, of the parent route template. So student template will be inserted in the students main outlet. Not students/index, because it's the sibling. This is the reason why all your content is replaced. And the student/index will be inserted in student
Second case
The index route is implied
Templates:
<script type="text/x-handlebars" data-template-name="students">
... omitted ...
<div class="well">
Expecting to render student template here:
<br />
{{ outlet }}
</div>
</script>
<script type="text/x-handlebars" data-template-name="student">
<h2>Student</h2>
<h3>{{name}}</h3>
<h4>{{grade}}</h4>
<h4>{{gpa}}</h4>
</script>
This time, like the previous sample, the resolution of the templates don't change. But this time we don't have the student/index. So first is rendered the student in students outlet, after because the student/index is missing, it's is ignored. The final result is the template where you expect.
Summary
Using the default conventions. Templates will be rendered in the parent, not sibling, parent route template.

AngularJS dynamically set param of ngInclude based on route

I'm trying to dynamically include a template into my index.html. The general structure of index.html is:
<body>
<header ng-controller="Main">
<section>
<!-- global stuff -->
</section>
<section ng-include="moduleName + '/views/menubar.html'">
<!-- module-based stuff -->
</section>
</header>
<div id="view" ng-view></div>
</body>
Sample URL
example.com/<app_name>/index.html#/<module_name>[/method_name]
I can't figure out how to update $scope.moduleName when the route changes. My trouble is two-fold:
The header's controller is Main, not the controller associated with the view, so I can't? update $scope.moduleName from the view's controller (because Main and the view's controller are siblings).
In Main, I tried setting a $scope.$on('$routeChangeSuccess',…), but apparently it is not notified of route changes.
I've thought of setting up a $rootScope.$on listener (as described in SO#15355346) for the route change and broadcasting down to children, who then emit back up their route, which is broadcasted back down so it is available to Main. But that seems heinous.
And I would really prefer to keep the header outside of ng-view.
EDIT I noticed that $route.current.scope has an object named with module_name (possibly because the name of the controller associated with the route's module_name is the same). I'm wondering if I might be able to somehow use the name of that object…
It's hard to say what's wrong in your code without the full picture. Things you show look fine to me.
Please see this plunk I've created to display the ability to do it. Take note that you also can extend route objects with custom properties, like moduleName here:
$routeProvider.when('/page1', {
template: 'one',
controller: 'one',
moduleName: 'firstModule'
});

Categories

Resources