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>
Related
I'm building my first lavavel website from scratch and I've run into a behavioral issue with a few routes.
Here is the relevant code for my routes file:
Route::get('work', 'PageController#work');
Route::get('work/{item}', 'PageController#workitem');
And here are the relevant methods:
public function work() {
return view('pages.work');
}
public function workitem($item) {
$v = 'work.'.$item;
if(view()->exists($v)) {
return view($v);
} else {
return view('errors.noitem');
}
}
And here is the relevant part of my view:
#extends('layout')
#section('content')
...
<div class="workflex">
<a class="workitem" href="/work/test"></a>
<a class="workitem" href="/work/test2"></a>
</div>
<div id="loadContent" class="loadContent">
#yield('insert')
</div>
...
#stop
It is worth mentioning that I intend to load the individual workitem pages with PJAX. I have views that the PJAX loads into the the "insert" section based on the URL:
$(document).pjax('a.workitem', '#loadContent');
The user loads the initial work page at the /work subdirectory, and clicks a button to load /work/item pages with PJAX. As the routes suggest, I also want the user to be able to enter a workitem into the URL and be directed to the work page already loaded with that item. This whole system behaves as intended... until I added the following jquery to work.blade.php:
$(document).ready(function() {
$('#loadContent').load("/work/init", function() {
myFade('#loadContent > *', 1); //ignore this function, it's an animation irrelevant to my problem
});
});
This is here as an attempt to load a initial message inside the PJAX loading div #loadContent to tell the user to select a workitem. However, a side effect of this is that now whenever I browser to a /work/item directly (PJAX still loads the pages correctly) the document triggers this jquery and the message overrides the page content.
I was brainstorming ways to allow the work() method in my controller to trigger something that loads this script or passes just the work/init view into the "insert" section.
What do you think would be the best way to solve this? Your answers are greatly appreciated.
I was able to answer my own question. I forgot about the route optional parameters. I changed/added these things:
Route::get('work/{item?}', 'PageController#work');
and in my controller:
public function work($item = 'init') {
$v = 'work.'.$item;
if(view()->exists($v)) {
return view($v);
} else {
return view('errors.noitem');
}
}
Works perfectly now!
I have very small web page with emberjs, where I want to show some item list and openlayers map for them, and another map for selected item.
Something like that:
<script type="text/x-handlebars" id="list">
<div class="list">
<div id="list_map"></div>
</div>
{{outlet}}
</script>
<script type="text/x-handlebars" id="list/item" >
<div class="item">
<div id="item_map"></div>
</div>
</script>
<script>
function showListMap() {
listMap = new ol.Map({target:'list_map'});
}
function showItemMap() {
itemMap = new ol.Map({target:'item_map'});
}
</script>
There is no problem to display map for list:
model: function(params) {
var content = [];
var url = 'http://localhost:8080/app/list';
$.ajax({
url: url,
success: function(surveys) {
content.pushObjects(surveys);
showListMap();
}
});
return content;
}
and I have action in item controller that is executed, when opening selected item, but if I try to create item map there (in controllers action) it fails (afaik because there is no such div at that moment in DOM).
So if I could execute action or my function after div is already add to DOM, it should work.
And question would be, how to execute something after template is added to DOM, or that's completely wrong way to do such stuff (than what would be correct ember way)?
I can't say much with seeing full code. But to execute some code after the DOM is rendered you schedule a function on the the run loops afterRender queue.
Ember.run.scheduleOnce('afterRender', this, function() {
//The div should be available now.
});
But if you really need to touch the DOM I recommend you wrap your map code in a component. A component gets a didInsertElement where you can write your maps initialization code.
var component = Em.Component.extend({
setup: function() {
//Do you map init here.
}.on('didInsertElement')
});
There unfortunately isn't a really good route or controller hook that fires off after a page has already rendered. I believe the reason for this is that the developers of Ember think it is an anti-pattern to directly talk to the DOM.
That being said, I think it sometimes is quite handy for complex UI on otherwise static web pages. If you want to do some sort of jquery or use the DOM API after a route has rendered, you can do the following in your route file (as #Dainius correctly points out)
routeName.js
import Route from '#ember/routing/route';
import jQuery from 'jquery';
export default class myRouteFile extends Route {
manipulateDom = function() {
$("#myDiv").css( "color", "red" );
}
init() {
this._super(...arguments)
Ember.run.scheduleOnce('afterRender', this, this.manipulateDom)
}
}
I would like to know which is the proper way to navigate between pages using ajax calls.
An example, we got this 3 html pages.
users.html (with users.js which initializes it and has its own functions)
cars.html (with cars.js which initializes it and has its own functions)
bills.html (with bills.js which initializes it and has its own functions)
What would be the proper way to go from users.html to cars.html ? I got this problem because I dont know how to "load" the cars.js after doing the ajax call in users.html.
¿If I load it with $.getScript(), how can I remove the users.js after adding the cars.js?
Thanks.
You can try to build a SPA (Single Page Application). You will have one index html file that uses the other html files as templates. For example you have a div main container whose content is replaced with users.html/cars.html/bills.html upon clicking a link.
Routing helps you get that done without refreshing the page. It also supports history.
Look up dependency injection so that you learn how you can download only the js files you depend on.
If you don't use routing and you only change the page content you lose history which is a really neat thing to have.
SPA with Routing and Templating
Routing with Sammy.js
Examples:
<body>
Cars
Bills
<div id="wrapper"></div>
<script src="jquery.js"></script>
<script src="sammy.js"></script>
<script>
(function() {
app.router = Sammy(function () {
var selector = '#wrapper';
this.get('#/cars', function() {
$.get('cars.html', function (view) {
$(selector).html(view);
});
this.get('#/bills', function() {
$.get('bills.html', function (view) {
$(selector).html(view);
});
});
});
app.router.run('#/cars'); //Link to load on app opening
}());
</script>
</body>
You can call page with $.get() like
$.get( "cars.html", function( data ) {
$(document).html(data);
alert( "Load was performed." );
});
In cars.js use all functions with $(document).ready()
but all functions must be:
$(document).on("yourevent","selector",function(){
});
while you load page cars.js will load if you import it in cars.html page
Read more about jquery.get() and jquery.on()
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')
});
I am working on a single-page web site targeted for mobile users (eventually going to be ported to Phonegap). I have broken down my screens into 'cards', which are basically just <div>s that I am showing/initializing/hiding as needed.
Currently I am having trouble deciding on the proper structure to use in order to implement linking these panels together into a coherent app. My current implementation goes something like this (currently using Knockout as I am familiar with it):
//Javascript
var LoginCard = function() {
this.goToRegister = function() {
// IF registerCard is not initialized
// THEN ko.applyBindings(new RegisterCard(), document.getElementById('registerCard'));
// ELSE $('#registerCard').show();
};
this.doLogin = function() { /* Goes to home card after login */ };
}
var RegisterCard = function() {
this.goToLogin = function() { /* Goes back to login card */ };
this.doRegister = function() { /* Goes to login card after reg */ };
}
ko.applyBindings(new LoginCard(), document.getElementById('loginCard'));
//HTML
<div id="loginCard">
<button data-bind="click: goToRegister" id="btnReg">Register Account</button>
<button data-bind="click: doLogin" id="btnLogin">Login</button>
</div>
<div id="registerCard">
<button data-bind="click: goToLogin" id="btnBackToLogin">Back To Login</button>
<button data-bind="click: doRegister" id="btnDoReg">Submit Registration</button>
</div>
As you can see, the linking occurs within the view model itself, so the different view models (e.g. loginCard, registerCard, homeCard) become tightly coupled with each other.
A more "low-level" alternative would just be to use jQuery to bind the button events so that each card does not have to know details about the other cards:
//But this means I have to specify a ton of unique IDs for all the elements in the page.
$('#btnReg').click(function() { /* Initialize and go to registerCard. */ });
I also thought of using hash-routing/pushState so while the click events are still inside each view model, all it has to know is the URL to go to? Something like:
var LoginCard = function() {
this.goToRegister = function() {
window.location.hash = 'register';
//or history.pushState('state', '', 'register';
};
}
This is my first attempt at creating a single-page application, so I am really confused about design choice. Which one would be better, or can anyone suggest the standard way to go regarding this?
I recommend you to create another object for the routing which depends on routing library such as SammyJS or CrossroadsJS.
Please refer my hobby project, MyStory.Spa, it is also single page application style web (not for the mobile app), which is using SammyJS for browser level routing.
In the MyStory.Spa architecture, webapp/app/infra/router.js takes a role for the routing and detailed information about routing, view, viewmodels are in the /webapp/app/infra/routing.table.js.
In this way you can decouple View, ViewModel, Model, Data Service, Routing and so on.