This issue has been stumping me for days. I need a subnav to display under the main nav in the application template when a user visits the 'about' page. I feel like I must be missing some vital concept because I keep reading that if something is extremely hard to do in Ember than you're probably doing it wrong. And I feel like Ember should be able to handle a simple subnav with ease.
I would like the subnav to display on the skinny white horizontal bar below the main nav when "ABOUT" is clicked.
I can't put the subnav in the about template since the nav code is in the application template.
My Router:
App.Router.map(function() {
this.resource("about", function() {
this.route("philosophy");
this.route("leadership");
this.route("staff");
this.route("affiliations");
});
this.route("conditions");
this.route("programs");
this.route("testimonials");
});
I can't render a partial inside the application template because I only want it displayed when someone is at the /about url.
I've tried plain old jQuery show and hide with this:
App.ApplicationController = Ember.ObjectController.extend({
currentRouteChanged: function() {
if(this.get('currentRouteName').indexOf('about') > -1) {
$("ul").removeClass("sub-nav-list-hide");
$("ul").addClass("sub-nav-list-show");
}
}.observes('currentRouteName')
});
And it works when you click about, but when you hit the back button or navigate to another page the subnav doesn't hide.
I'm stuck and I feel like I'm making this way too difficult.
I would set a property in the application controller from within App.AboutRoute
App.AboutRoute = Ember.Route.extend({
activate: function(){
this.controllerFor('application').set('renderAboutSubNav', true);
},
deactivate: function(){
this.controllerFor('application').set('renderAboutSubNav', false);
}
});
and then check the property in the application template.
{{#if renderAboutSubNav}}
{{render 'about/subnav'}}
{{/if}}
Here is an example jsbin
That looks elegant to me!
We can do in application controller something similar.
App.ApplicationController=Ember.Controller.extend({
renderAboutSubNav:function(){
var reg = new RegExp("^about\.");
return reg.test(this.get('currentPath'));
}.property('currentPath')
});
Related
My ember app is set up with a list of posts on the left and a view for an individual post on the right. When one of the posts on the left is clicked it's content is rendered in the view on the right.
This is the code I'm using to add syntax highlighting to a post.
App.PostView = Ember.View.extend({
didInsertElement: function() {
$('pre code').each(function(i, e) {hljs.highlightBlock(e)});
}
});
When the first post view is rendered, it has the syntax highlighting, but when I click on a different post and it's content gets loaded into the post view the syntax highlighting does not get applied. How can I make it so that the highlighting applied every time a post is rendered?
I can only guess without a more comprehensive example. Is PostView what gets created in the right panel? If so, then you need to constrain your view rendering to the stuff inside the view.
In your example, $('pre code') will target all pre code elements inside the document. Try this.$('pre code'), or whatever element/selector needs to be highlighted within the view.
This may be not the cleanest way to do the job, but you could try adding observer to the controller's model, and make required changes. But this will only work, if the model itself changes.
Like this:
postHasChanged: function() {
if (this.get('state') === 'inDOM') {
$('pre code').each(function(i, e) {
hljs.highlightBlock(e)
});
}
}.observes('controller.model')
Ok, i'm a really newbie to Ember JS, but i'm having a play and working my way through things.
So far I'm really liking it, but…
I wanted to use something like: https://github.com/ed-lea/jquery-collagePlus, which created a masonry style layout.
I have create the route, and the navigation to that view, but… how do you apply the effect?
Normally a:
$(window).load(function () {
$('.Collage').collagePlus();
});
would do the job at the bottom of the page, but i'm guessing popping in a:
App.GridRoute = Ember.Route.extend({
afterModel: function(){
$('.Collage').collagePlus();
}
});
Might be better, but that's not working…
any help, pointers on this welcome, be gentle as i'm not understanding it quite yet!
PS. i'm also using bootstrap and bootstrap ember (probably doesn't matter…)
The place to do it it's the View, handling the didInsertElement event. I believe the View it's a good place to isolate any logic related to the DOM.
App.GridView = Ember.Route.extend({
classNames: ['Collage'],
didInsertElement: function(){
this.$().collagePlus();
}
});
A useful link:
Hope it helps!
I'm creating a single page home site and would like to reduce initial page load time and save user bandwidth by lazy loading views that are below what is currently visible. The home page will be rather long, with a nav, header, several content sections, and a footer. My goal is to initially loading a static layout container with the nav and sticky footer along with the 'root' angular app. Scrolling or clicking on a nav link will cause the next viewable view to load (clicking a nav link that jumps down past several views should load all the views a user will jump past). I know there is a jQuery lib for this task, but I'd like to stick to Angular.
Is there an easy way to conditionally load views this way in Angular?
Here's what I came up with, just as a quick example. There are many ways you could accomplish this. If you want more fine tuning, you could even write your own directive instead of using ng-include/ng-repeat.
Live demo here
Hmm, plnkr is having some issue right now. If the page will even load, it seems to sometimes have trouble finding the templates (see the console log..it is trying to load them, so the code is working fine). Here's a jsbin demo also, but the templates are just going to load nothing (empty).
<div ng-repeat="lazy in loaded">
{{lazy}}
<div ng-include="lazy"></div>
</div>
<button ng-click="loadNext()">Load Next</button>
<button ng-click="unload()">Reset</button>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
var toLoad = [ //list the templates to be loaded
'tmpl.html',
'tmpl2.html',
'tmpl3.html'
];
$scope.loaded = []; //anything in here will be loaded to the page
$scope.loadNext = function() {
if (toLoad.length) { //if there are any item left to load
$scope.loaded.push(toLoad.splice(0, 1)[0]); //move first item to "loaded"
}
};
$scope.unload = function() {
toLoad = $scope.loaded.splice(0, $scope.loaded.length); //move all items back to "toLoad"
};
});
I am using the Hot Towel template by John Papa. I have a html view called nav.html, which contains the header portion of my spa. Within that, i need to display the name of the person that is logged into the system (i have a server side utility class that handles the query).
The following is from the html in the nav.html view for that-
data-bind="text: LoggedInAs"
Here is the viewmodel code (nav.js)-
define(['services/logger'], function (logger) {
var vm = {
activate: activate,
title: 'Nav View'
};
return vm;
//#region Internal Methods
function activate() {
logger.log('Nav View Activated', null, 'Nav', true);
return true;
}
//#endregion
});
My problem is that i am not sure how to do this. i tried adding nav.js to my viewmodels folder, but the javascript does not run. I thought durandal would have picked it up like the other viewmodels. The only difference between the nav.js and the other view models is that the other view models are triggered by clicking on a link (wired through route.mapnav).
What am i missing here? How do i get the javascript to run without a user clicking on a link? When the page loads, I need nav.js to run in order to populate the LoggedInAs data-bind.
Make sure that you are activating your nav view. In the example code you have given in the comment above, it would need to be this:
<header> <!--ko compose: {view: 'nav', activate: true} --><!--/ko--> </header>
I just started using Backbone.js on a somewhat complex application. In it, I have a login page which has no navigation at all, and an admin and user section, each with its navigation bar. My question is, what is a good way of representing a dynamic navigation bar through backbone.js. I've thought about about creating three different parent views for the login, admin, and user sections. In each view, I can instantiate (or not) the appropriate navigation bar.
I think you are on the right track with the parent view idea. What I would do is set up a main container and use a router to fill in the appropriate "page" view. eg. admin, user. In those parent views you will have two more views. One for your nav bar and one for the content. In the nav bar view you can assign your events and for the various navigation buttons. Make sure you properly remove views and undelegate events a good example is:
Zombie View Management. Undelegating Events
index.html
<div id="main-container">
</div>
router.js
app.Router = Backbone.Router.extend({
routes :{
"" : "showLogin",
"user" : "showUser",
},
initialize : function(app){
this.RM = app.RegionManager;
},
showUser : function(){
this.RM.show(new app.UserView());
},
showLogin : function(id){
this.RM.show(new app.LoginView());
}
});
region-manager.js
var app = app || {};
app.RegionManager = {
el : "#main-container",
show : function(view){
if(this.current)
this.current.close();
this.current = view;
this.current.render();
$(this.el).html(this.current.el);
}
};
user-view.js
app.UserPageView = Backbone.extend({
initialize : function(){
this.children.nav = new app.UserNavBar();
this.children.content = new app.UserContent();
},
render : funciton(){
this.$el.html(this.children.nav.render().el);
this.$el.html(this.children.content.render().el);
}
});
Let your views declare their header necessities and have your view manager consume them. I like to define a header property with text and a buttons array - each having an event reference and various things like an enabled() delegate. My view manager, when loading and displaying this view, will read the property and turn it in to a model that the header binds to. If no header property exists on the view, no header will be created for it.