bind values to application.hbs from different routes - javascript

In Ember.js (version 2.5.1), I have the following code in my application.hbs:
<div class="content-wrapper">
<section class="content-header">
<h1>
{{title}}<small>{{description}}</small>
</h1>
</section>
<section class="content">
{{outlet}}
</section>
</div>
Where should I declare {{title}} and {{description}} properties so they can change depending on the current route? I thought of generating an application controller (ember g controller application) which works fine for the index route, however, I am unable to change these properties if I navigate to other routes in my application.

I would design my application.hbs like this
{{partial "app_navbar"}}
<div class="container">
{{outlet}}
</div>
{{partial "app_footer"}}
And to create a route dependent header i would make a component content-header
templates/components/content-header.hbs
<div class="content-header">
<h1> {{params.title}} - <small> {{params.description}} </small> </h1>
</div>
And in your custom route's controllers
export default Ember.Controller.extend({
navbarParams: {
title: 'Foo',
description: 'Bar'
}
});
And in your custom route's template
{{content-header params=navbarParams}}
{{! Your other content here}}

Related

Is there a way to tell if a yielded component's has-block is empty?

I am trying to make a contextual component that can provide a default header when one is not passed in the yielded block. Normally, I could use the has-block helper to tell if a component has block content but this component will always have block content. I think what I need is a way to tell if the yielded component has block content. For example:
{{! panel.hbs }}
<header>
{{yield header=(component "blank-template")}}
{{#if (yieldedHeaderEmpty)}}
<h1>My Default Header</h1>
{{/if}}
</header>
<section>
{{yield body=(component "blank-template")}}
</section>
<footer>
{{yield footer=(component "blank-template")}}
</footer>
I only want the default header to show when the yielded "header" section is empty. I could create a header component which then could use the has-block like so:
{{! panel.hbs }}
<header>
{{yield header=(component "my-header")}}
</header>
...
{{! MyHeader.hbs}}
{{#if (has-block)}}
{{yield}}
{{else}}
<h1>My Default</h1>
{{/if}}
Functionally I think this will work but the only purpose of the "my-header" component would be for this "panel" component and seems wasteful. Open to ideas. Thanks!
Ember core recently accepted an RFC for "named blocks" which is designed exactly for this purpose. https://github.com/emberjs/rfcs/pull/460. With this feature, we can name the yieldable blocks and access them with their names, like:
template.hbs:
<Panel>
<:header>This is a customized header</:header>
</Panel>
panel.hbs:
{{#if (has-block "header")}}
{{yield to="header"}}
{{else}}
<header> This is the default header </header>
{{/if}}
This is yet to be landed in the Ember core. Luckily we have an official polyfill that supports this feature from 3.12.4: https://github.com/ember-polyfills/ember-named-blocks-polyfill

Dynamically determine existence of Ember component?

I was looking through the ember-htmlbars package and discovered this util for determining if a component is available? https://github.com/emberjs/ember.js/blob/master/packages/ember-htmlbars/lib/utils/is-component.js
Is there any way to use this from my app? I'm building a dashboard-type interface and some of the dashboard widgets have optional actions. In essence I'd like to do something like:
<div class="panel panel-default">
<div class="panel-body">
{{component model.displayComponent model=model}}
</div>
{{#if isComponent(model.actionComponent) }} <!-- this would be a property -->
<div class="panel-footer">
{{component model.actionComponent model=model}}
</div>
{{/if}}
</div>
My fallback is to put a blank action component for each of my widgets that don't have one, but it would be cleaner to be able to check to see if they exist first.
you can create helper is-component
export default Ember.Helper.extend({
compute([name]) {
return this.container.registry.has('component:' + name);
}
})
and use it like {{#if (is-component model.actionComponent) }}

Nested vue.js instances/elements

This may sound like a real noob question, but I'm pretty new to MVVM... or even MVC in JS, so sorry in advance.
I'm playing about with vue.js, and loving the simplicity of it so far. But for what I am trying to do, I think I need to go about it a different way.
I want to nest Vue instances/elements inside each other, but of course, the parent will then use the child when it reads through the DOM on init.
For the sake of arguments, below is an example of what I mean, I am not doing anything like this, but this is the simplest way to example what I mean:
<body>
{{ message }}
<div id="another">
{{ message }}
</div>
</body>
Then my JS for example would be:
new Vue({
el: "body",
data: {
message: "I'm the parent"
}
});
new Vue({
el: "#another",
data: {
message: "I'm the child"
}
});
The outcome would be:
<body>
I'm the parent
<div id="another">
I'm the parent
</div>
</body>
Now I completely understand why it is doing this and in fact, it should do this, but my example is just trying to illustrate how I would do something like this?
In my real life project, I have a v-class on my body that changes when stuff happens in the body (in numerous places) but of course my body will also want other instances of vue that do other stuff.
how would I go about nesting? Is there feature in vue to deal with this? Do I need to deal with components? Or maybe, fetch the body from within a child element (e.g. like jQuery would with $("body")) then manipulate it within the Vue instance?
Hope this question isn't too stupid and someone can point me in the right direction.
Thanks
Think components.
http://vuejs.org/guide/components.html
Create a Vue instance on the body as you have above, but anything nested in that is a component. Pass data via props.
Passing in data via props is only one way to do it. Nesting components and inheriting from the parent works fine as well.
Example: http://jsfiddle.net/hajkrupo/3/
<encapsulated-component inline-template>
<header>
<cart-status></cart-status>
</header>
<cart></cart>
</encapsulated-component>
You can do this with <slot> tags. Here is an example.
1.So, first, you need to do is creating a basic layout component, like this.
You need to add <slot> tag whereever you want. Very important think is the name attribute on <slot> tag.
var basicLayout = Vue.component("basic-layout", {
template: `
<div class="basic-layout">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
`
});
2.Then create your custom component. I created myHeader component to show you, how it works.
var myHeader = Vue.component("my-header", {
template: `
<div class="header">
<ul>
<li>HOME</li>
<li>ABOUT</li>
<li>CONTACT</li>
</ul>
</div>
`
});
3.Put this sample code in your HTML file.
To put some content in current slot, just use the slot attribute in your component or your tag.
<div class="app">
<basic-layout>
<my-header slot="header"></my-header>
<p>Content in <main> tag</p>
<p slot="footer">Content in footer</p>
</basic-layout>
</div>
4.The result will be like this:
<div class="app">
<div class="basic-layout">
<header>
<div class="header">
<ul>
<li>HOME</li>
<li>ABOUT</li>
<li>CONTACT</li>
</ul>
</div>
</header>
<main>
<p>Content in <main> tag</p>
<main>
<footer>
<p>Content in footer</p>
</footer>
</div>
</div>
Please, see the documentation in official page of Vue.js
Just click link here for more info.
Here is example in jsfiddle

MeteorJS template placeholder

Iam getting started with MeteorJS/Iron Router/Blaze and I'm trying to figure out how to set placeholder for template.
I have a menu and a footer, which will change only partialy, but between them is the main content which should be based on current route. Point is that i need some sort of pointer, like in angular "ng-view".
Eg.
<menu></menu>
{{some sort of placeholder}}
<footer></footer>
and in router:
Router.route('/', function () {
//render some template exactly into placeholder, dont append it to the bottom
});
Maybe there is something wrong with my understanding of meteorjs templating, I just base my way of solving this problem on angular templating.
not sure I got your question but here is an answer:
You can do that with the {{> yield}} tag. It will define an dynamic area which will show the view corresponding to the current route.
You can also "design" a layout for your entire app, like you did, for example layout.html :
<template name="layout">
<div class="container">
<header class="navbar">
<div class="navbar-inner">
<a class="brand" href="{{pathFor 'home'}}">My app</a>
</div>
</header>
<div id="main" class="row-fluid">
{{> yield}}
</div>
</div>
</template>
And tell Iron-Router that your app has to fit this layout :
Router.configure({
layoutTemplate: 'layout'
});
// Then just define your routes
Router.map(function() {
this.route('home', {path: '/'});
});
You may notice I used {{pathFor 'home'}} in the layout. Iron Router let you use route "names" so it won't do anything if you change the URL.
I suggest you read an awesome book called Discover Meteor !

Ember.js - Application <div/> is rendered twice?

I'm using the following Ember.js stack:
DEBUG: -------------------------------
DEBUG: Ember : 1.1.2
DEBUG: Handlebars : 1.0.0
DEBUG: jQuery : 2.0.2
DEBUG: -------------------------------
I declared an application.hbs Handlebars template which renders my App.ApplicationView
{{#view App.ApplicationView}}
{{outlet 'modal'}} {{outlet 'notificationCollection'}}
{{#if isUserAuthenticated}}
{{render sidemenu authenticationState=isAuthenticated}}
{{outlet 'upperNotification'}}
<div id="main" class="main">
{{outlet}}
</div>
{{else}}
{{outlet}}
{{/if}}
{{/view}}
and for debugging purposes I added the gotcha to the classNames array of App.ApplicationView. When I now inspect the DOM, I can see that App.ApplicationView is rendered twice (and also boxed):
...
<div id="appRoot" class="ember-application">
<div id="ember444" class="ember-view gotcha">
<div id="ember445" class="ember-view gotcha">
...more content..
</div>
</div>
</div>
...
EDIT:
I should have tried it first, before posting it here at stackoverflow... if I remove the {{#view App.ApplicationView}}{{/view}} declaration, it get's only rendered once, as expected ;)
So, the question which remains a miracle to me is is Ember.js really generating an enclosing <div id="ember666" class="ember-view"></div> for every {{outlet}}??
Why would Ember.js handle it this way? How can I prevent it from rendering App.ApplicationView twice? And, besides that, is Ember.js really generating an enclosing <div id="ember666" class="ember-view"></div> for every {{outlet}}? (I'm seeing this behaviour within my application)
By default, yes {{outlet}} will enclose your template in a <div>. However, you can change that behavior by specifying a view class on the outlet and defining the view class' tagName property to whatever you want.
For example, the outlet
{{outlet viewClass=App.HeaderContainer}}
With view
App.HeaderContainer = Ember.ContainerView.extend({
tagName: 'header'
});
will wrap the outlet in a <header> tag.

Categories

Resources