I'm trying to preserve the full markup of a template, including the class on the root node when using a marionette region. I'm also trying to avoid creating an extra wrapping div. I've solved the problem, but in a way which I don't think is satisfactory.
I am creating and rendering a layout like this:
MyApp = new Backbone.Marionette.Application();
MyApp.addRegions({
mainRegion: "#main"
});
AppLayout = Backbone.Marionette.Layout.extend({
template: '
<div class="row">
<div class="col-md-8"></div>
<div class="col-md-4"></div>
</div>
'
});
var layout = new AppLayout();
MyApp.mainRegion.show(layout);
layout.show(new MenuView());
And the result is that my template is rendered like this:
<div id="main">
<div>
<div class="col-md-8"></div>
<div class="col-md-4"></div>
</div>
</div>
Notice, the class="row" is missing from the root node of the template. It appears that marionette is removing the root div from my template, and then wrapping the contents in a new div.
I have managed to hack a solution to this like this
AppLayout = Backbone.Marionette.Layout.extend({
template: '
<div><!-- sacrificial div -->
<div class="row">
<div class="col-md-8"></div>
<div class="col-md-4"></div>
</div>
</div>
',
onRender: function () {
// get rid of that pesky wrapping-div
// assumes 1 child element.
this.$el = this.$el.children();
this.setElement(this.$el);
}
});
I'm adding an extra root div (my sacrificial div) to my template which marionette removes, and then I'm telling marionette to use the first child as the layouts 'el' (as per Turning off div wrap for Backbone.Marionette.ItemView).
This seems crazy!
Can somebody suggest a better way?
EDIT: n.b. I'd like to keep all the template logic in the template, so don't want to have to use code in my view to specify the class on the root node - if I do this, I end up with a maintenance headache.
Try with
AppLayout = Backbone.Marionette.Layout.extend({
template: '
<div class="col-md-8"></div>
<div class="col-md-4"></div>
',
className: "row"
});
AppLayout is missing its region(s).
AppLayout = Backbone.Marionette.Layout.extend({
template: '
<div class="row">
<div id="region1" class="col-md-8"></div>
<div id="region2" class="col-md-4"></div>
</div>
',
regions: {
region1: '#region1',
region2: '#region2'
}
});
Then at your instantiated layout:
layout.region1.show(new MenuView());
layout.region2.show(new MenuView());
Instead of assigning the template to a string, compile the HTML into a template function with underscore. Something like this:
template: _.template(
'<div class="row">' +
'<div class="col-md-8"></div>' +
'<div class="col-md-4"></div>' +
'</div>'
)
Related
I'm creating a component with a background being provided as a its attribute, like this:
<overlay-card src="https://static.pexels.com/photos/51387/mount-everest-himalayas-nuptse-lhotse-51387.jpeg" color="rgba-bluegrey-strong">
My component template:
`<div class="card card-image mb-3" style="background-image: url({{src}});" [ngClass]="(alignment==='left')?'text-left':(alignment==='right')?'text-right':'text-center'">
<div class="text-white d-flex py-5 px-4 {{color}}"
>
<ng-content></ng-content></div>
</div>`
What I get is:
// WARNING: sanitizing unsafe style value background-image: url(https://static.pexels.com/photos/51387/mount-everest-himalayas-nuptse-lhotse-51387.jpeg); (see http://g.co/ng/security#xss).
As it's a <div>, I cannot really count on [ngSrc].
You can use ngStyle for that:
<div [ngStyle]="{'background-image': 'url(' + src + ')'}">...</div>
You should make this url trusted in your component code and a litle bit change you component template like this:
import {DomSanitizer} from '#angular/platform-browser';
...
export class OverlayCard {
#Input() src: string;
constructor(private sanitizer: DomSanitizer) {
this.trustedSrc = sanitizer.bypassSecurityTrustUrl(this.src);
}
<div class="card card-image mb-3" style="background-image: url({{trustedSrc}});" [ngClass]="(alignment==='left')?'text-left':(alignment==='right')?'text-right':'text-center'">
<div class="text-white d-flex py-5 px-4 {{color}}">
<ng-content></ng-content>
</div>
</div>
I would like to use two layouts for my Aurelia app.
Home - FAQ - Login page don't contain a sidebar;
But everything else do contain this sidebar.
My architecture, with a sidebar is pretty complicated in HTML and is like:
div.container
div.sidebar
div.sidebar_content
div.site_content
So i can't just enable or disable the sidebar because it contains the view.
I have to make two pages like "app.html", defined in main.js, but how tell to Aurelia "Choose app.html for this page, and app2.html for this other page"?
I have found the setRoot function but i have bugs with it (the routes does not work properly when i change setroot)
Thank you for your answers
The router supports the concept of "layouts." This is documented here: http://aurelia.io/hub.html#/doc/article/aurelia/router/latest/router-configuration/10
Basically, you specify a layout for each route (you can specify a default layout on the router-view custom element:
app.html
<router-view layout-view="./layout-with-sidebar.html"></router-view>
app.js
export class App {
configureRouter(config, router) {
config.title = 'Aurelia';
var model = {
id: 1
};
config.map([
{ route: ['home', ''], name: 'home', title: "Home", moduleId: 'home', nav: true },
{ route: 'no-sidebar', name: 'no-sidebar', title: "No Sidebar", moduleId: 'no-sidebar', nav: true, layoutView: 'layout-without-sidebar.html' }
]);
this.router = router;
}
}
layout-with-sidebar.html
<template>
<div class="container">
<div class="row">
<div class="col-sm-2">
<slot name="sidebar"></slot>
</div>
<div class="col-sm-10">
<slot name="main-content"></slot>
</div>
</div>
</div>
</template>
layout-without-sidebar.html
<template>
<div class="container">
<div class="row">
<div class="col-sm-12">
<slot name="main-content"></slot>
</div>
</div>
</div>
</template>
home.html
<template>
<div slot="sidebar">
<p>I'm content that will show up on the right.</p>
</div>
<div slot="main-content">
<p>I'm content that will show up on the left.</p>
</div>
</template>
no-sidebar.html
<template>
<div slot="main-content">
<p>Look ma! No sidebar!</p>
</div>
</template>
I have a Markup annotation on some of my sass source, like so:
// Headings
//
// Markup:
// <h1 class="{$modifiers}">H1 Heading</h1>
// <h2 class="{$modifiers}">H2 Heading</h2>
// <h3 class="{$modifiers}">H3 Heading</h3>
// <h4 class="{$modifiers}">H4 Heading</h4>
// <h5 class="{$modifiers}">H5 Heading</h5>
// <h6 class="{$modifiers}">H6 Heading</h6>
//
// .subheader - Subheader class
// .secondary-header - Secondary header class
//
// Styleguide 4.1
In the generated output, I get output for the default stle and both of my modifier classes. However, they look identical. Upon inspecting the elements, it becomes clear that the template is not dereferencing the {$modifiers}
<div class="kss-modifier__name kss-style"> .subheader </div>
<div class="kss-modifier__description kss-style"> Subheader class </div>
<div class="kss-modifier__example">
<h1 class="{$modifiers}">H1 Heading</h1>
<h2 class="{$modifiers}">H2 Heading</h2>
<h3 class="{$modifiers}">H3 Heading</h3>
<h4 class="{$modifiers}">H4 Heading</h4>
<h5 class="{$modifiers}">H5 Heading</h5>
<h6 class="{$modifiers}">H6 Heading</h6>
</div>
This is using kss-node 2.0.2
Any thoughts on what I might be doing wrong here? I've compared my template to a template on another project that works and I don't see any differences in the relevant section.
Since then I think kss has changed a bit or you've used a wrong modifier class ?
According to the specs:
If you include {{modifier_class}} in the markup, the generated style
guide will be able to use the correct CSS class when it displays the
sample for each of the modifiers.
https://github.com/kss-node/kss/blob/spec/SPEC.md
I have a named view called myView in which I have two div elements that I want to show conditionally using ng-show based on whether the value of $scope.states['currentState'] is 'A' or 'B'. The value of $scope.states['currentState'] is changed when an anchor tag is clicked which calls the doStuff function on the myController controller.
The issue I am having is when the anchor tag is clicked and the doStuff function is clicked, it shows on the console that the value of $scope.states['currentState'] has been modified, but its not updating the myView named view accordingly.
Following is the code for app.js, myView.html and index.html files. The index.html file is being used as a <div ui-view></div> in an index.ejs file that I am rendering using Express with Node.js.
app.js
var app = angular.module("app", ['ui.router']).
config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
views: {
'': { templateUrl: 'partials/index.html' },
'myView#home': {
templateUrl: 'partials/myView.html',
controller: 'myController'
},
'myOtherView#home': {
templateUrl: 'partials/myOtherView.html',
controller: 'myController'
}
}
});
}])
app.controller("myController", ['$scope', function($scope){
var states = ['A', 'B'];
$scope.states = states;
$scope.states['currentState'] = states['currentState'] || 'A';
$scope.doStuff = function(toState) {
//doing stuff
$scope.states['currentState'] = toState;
console.log($scope.states['currentState']);
};
} ]);
index.html
<div class="main">
<div class="container">
<div class="row margin-bottom-40">
<div class="col-md-12 col-sm-12">
<div class="content-page">
<div class="row">
<div ui-view="myView"></div>
<div ui-view="myOtherView"></div>
</div>
</div>
</div>
</div>
</div>
</div>
myView.html
<div ng-controller='myController'>
<div ng-show="states['currentState'] == 'A'">
//displaying this div if the currentState is A
<a ng-click="doStuff('B')">Do stuff and show B</a>
</div>
<div ng-show="states['currentState'] == 'B'">
//displaying this div if the currentState is B
</div>
</div>
Could somebody help me understand that why am not getting the div with states['currentState'] == 'B' shown, even when I see the value of console.log($scope.states['currentState']) changed from 'A' to 'B' when the doStuff function is called in myController?
Edit:
Here is the demo of the issue I am facing.
Okay So I was mistaken in my comment.
The real issue was that you used {{}} in your ng-show which is not needed as these expect to take angular expressions.Also I would make current state a property of your scope as at the moment you are trying to make it a property of an array inside your scope.
Hope that helps! Below is the modified code for your view:
<div ng-controller='MainCtrl'>
<div ng-show="currentState === 'A'">
<a ng-click="doStuff('B')">Do stuff and show B</a>
</div>
<div ng-show="currentState === 'B'">
<a ng-click="doStuff('A')">Do stuff and show A</a>
</div>
</div>
EDIT: Working plunker http://plnkr.co/edit/1llQMQEdxIwu65MNoorx?p=preview
From this discussion here,
Allow a passed in variable to {{renderPages}} helper
I am trying to display a template within an existing {{renderPage}};
My Use case: I have a very simple high level body template
<template name="body">
{{> header}}
{{> notifications}}
<div class="content" id="content">
<div id="main-content">
{{{renderPage}}}
</div>
</div>
{{> footer}}
</template>
And as you can see, my main-content has the {{renderPage}}. This works great, when i set up a route:
'/home': 'home'
The route finds the template 'home' and replaces renderPage with that template. I want to expand that now and see if route templates can be placed within specific divs.
For example, in my home.html template:
<template name="home">
{{#if isAdmin}}
<h1>student</h1>
{{/if}}
<div id="inner_home">
{{renderPage innerHome}}
</div>
</template>
Is it possible to have a different route /home/tools : 'home_tools render it's template not in the highest main content div but within my child div inner_home?
EDIT:
I am evaluating an approach that just uses JQuery and the callback function of the meteor-router method to grab the template i am looking for and add it directly to the concerning div tag.
Something like:
var foundTemplate = _.template($('#item-template').html())
$('#div_example').html(foundTemplate); //
If anyone has a better approach, please let me know.
Sure.
client.js
Meteor.Router.add({
'/home/tools': function() {
Session.set("homeTemplate", "tools");
return 'home';
},
'/home/admin': function() {
Session.set("homeTemplate", "admin");
return 'home';
}
});
home.js
Template.home.homeTemplateTools = function() {
return Session.equal("homeTemplate", "tools");
};
Template.home.homeTemplateAdmin = function() {
return Session.equal("homeTemplate", "admin");
};
home.html
<template name="home">
{{#if isAdmin}}
<h1>student</h1>
{{/if}}
<div id="inner_home">
{{#if homeTemplateTools}}
{{> homeTools}}
{{/if}}
{{#if homeTemplateAdmin}}
{{> homeAdmin}}
{{/if}}
</div>
</template>