I'm trying to join common events to a route, and then extend the route as needed
Like this:
App.ScrollTopRoute = Ember.Route.extend({
renderTemplate: function() {
console.log('Hi this works ?');
window.scrollTo(0, 0);
}
});
Then I extend the route:
App.TodoRoute = App.ScrollTopRoute.extend({
model: function(params) {
return App.Todo.find(params.todo_id);
}
});
The problem is the events inside ScrollTopRoute are not launch
So which is the best way to join common routines for routes?
You are doing DOM related operations which should go into the didInsertElement of a view.
So for your window.scrollTo(0, 0) to work it should be defined in such a hook, assuming you have a todos template than this should work.
App.TodosView = Ember.View.extend({
didInsertElement: function() {
window.scrollTo(0, 0);
}
});
In the case you need common code to be executed in different classes one possible way is to create a Mixin and mix it into the classes that need it.
For example:
App.CommonMixin = Ember.Mixin.create({
myCommonFunction: function() {
console.log('this works');
}
});
App.ScrollTopRoute = Ember.Route.extend(App.CommonMixin, {
...
// myCommonFunction is available here
});
App.AnotheScrollTopRoute = Ember.Route.extend(App.CommonMixin, {
...
// myCommonFunction is available here
});
As for the Mixin, see here for a simple demo.
Hope this answers your question, if not let me know so I can improve it further.
Related
I'm building a custom wizard in knockout that dynamically loads knockout components during each "step" of the wizard. I've managed to get all of this working without much hassle, and it seems to work pretty well.
However, I'm wanting to implement some callbacks within the wizard when certain events happen. For example, before and after navigation.
Currently, one of my navigation functions looks like this:
this.goNext = function () {
if (!this.canGoNext()) return;
this.currentStep(this.pages()[this.currentIndex() + 1]);
this.loadPage();
}
I would like to build 2 callback functions called beforePageChange and onPageChange.
My general assumption is that beforePageChange would pass in a couple parameters, notably the current page and the next page. However, I also want it to be able to be observed from any other class utilization the wizard.
For example, on my parent page I would have something like:
this.wizard = Site.loadWizard(arguments);
this.wizard.beforePageChange(function(options) {
if (!options.currentPage.complete) return false;
// do stuff
return true;
});
In turn the wizard would execute its navigation commands and trigger the appropriate callbacks.
I feel like there's something I'm just fundamentally missing here.
Edit
My current version works as follows:
In the wizard:
this.canChangePage = ko.obserable(true);
this.beforePageChange = function (options) {
};
this.beforePageChangeHandler = function (options) {
this.beforePageChange(options);
// do stuff
return true;
};
this.onPageChange = function (options) {
};
this.onPageChangeHandler = function (options) {
this.onPageChange(options);
//do stuff
return true;
}
On the page implementing the wizard:
this.wizard = Site.loadComponent(params, function () {
this.wizard.beforePageChange = function (options) {
this.canChangePage(false);
};
}.bind(this));
I'm not sure if there's a better way to implement this, or if this is the best solution.
The solution Tomalak described in their comment (I think):
Since you already have access to the wizard instance, you can subscribe to its currentStep observable. To get notifications before it changes, you pass a third parameter: "beforeChange". (The second is the this context).
var Wizard = function() {
this.currentStep = ko.observable(0);
}
Wizard.prototype.next = function() {
this.currentStep(this.currentStep() + 1);
}
Wizard.prototype.prev = function() {
this.currentStep(this.currentStep() - 1);
}
var Page = function() {
this.wizard = new Wizard();
this.wizard.currentStep.subscribe(function(oldStep) {
console.log("Page work before step change from step", oldStep);
}, this, "beforeChange");
this.wizard.currentStep.subscribe(function(newStep) {
console.log("Page work after step change to", newStep);
});
}
ko.applyBindings(new Page());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="with:wizard">
<button data-bind="click: prev">back</button>
<span data-bind="text: currentStep"></span>
<button data-bind="click: next">next</button>
</div>
I want to write a simple mixin for a tooltip. I already know how to bind my mixin to DOM events:
componentDidMount: function() {
var el = this.getDOMNode();
el.addEventListener('mouseenter', this.mouseenter, false);
el.addEventListener('mouseleave', this.mouseleave, false);
},
...but I'd like to bind to the React events instead, to take advantage of its consistent event system. How do I do it?
I think you probably want to do this in the render method of the mixing component, by passing in the mixin's mouseenter and mouseleave handlers as props. I think one option might look like this:
var MouseMixin = {
getMouseProps: function() {
return {
onMouseEnter: this.mouseenter,
onMouseLeave: this.mouseleave
}
},
mouseenter: function() {
console.warn('mouseenter', arguments)
},
mouseleave: function() {
console.warn('mouseleave', arguments)
}
};
Then, in addition to mixing this in, you'd need to apply the behavior. In JSX in React 0.12, you can use the ... spread operator to help with this:
var Example = React.createClass({
mixins: [MouseMixin],
render: function() {
return (
<div { ...this.getMouseProps() }>
Hello world
</div>
)
}
});
See a working fiddle here.
I have this functionality associated with clicking a button:
'click .single-speaker-info a': function(ev, speaker){
ev.preventDefault();
Session.set('selectedDocId', this._id);
}
But I'd like it to happen upon hitting this route
Router.route('speaker', {
path:'/speakers/:_id',
template: 'speaker',
data: function(){
return Speakers.findOne(this.params._id);
},
//my attempted solution
selectedDocId: function(){
Session.set('selectedDocId', this._id);
}
});
But I can't find any documentation on how to execute a method on a route.
Here is the Template.helper Im using to get the property Im setting
Template.speaker.helpers({
editingDoc: function(){
return Speakers.findOne({_id: Session.get('selectedDocId')});
}
});
But I can't find any documentation on how to execute a method on a route.
Iron Router offers a number of hooks:
onRun <-- probably what you need
onRerun
onBeforeAction
onAfterAction
onStop
You could use Template.x.rendered, once the page is rendered, any code in that block will be executed. Of course this would not be in your router.
In your case:
Template.speaker.rendered = function() {
//Get data from router
var data = Router.current().data();
Session.set('selectedDocId', data._id);
}
I am trying to dynamically get and set a pageTitle for my sample Meteor app, ideally I'd like to use jQuery, but any other solution would be good too.
I am trying to do it the rough way by setting a session when a certain div class exists on the page, but it's not working for some reason.
Basically, I have this:
Template.layout.helpers({
pageTitle: function() { return Session.get('pageTitle'); }
});
And I want to do something like
if ($('section').hasClass('single')) {
Session.set('pageTitle', 'Post Page');
}
Any idea ho to make this work? thanks!
You need to call it in a controller or the templates rendered section like this:
Template.layout.helpers({
pageTitle: function() {
return Session.get('pageTitle');
}
});
// set when a page template renders
Template.posts.rendered = function() {
setPageTitle("Blog Posts");
};
// or with Iron Router on *every* route using some sort of variable
Router.onBeforeAction(function() {
var someDynamicValue = "FOO";
setPageTitle(someDynamicValue);
});
// or in an IronRouter Controller
PostsController = RouteController.extend({
onBeforeAction: function() {
setPageTitle("Blog Posts");
}
});
// helper function to set page title. puts a prefix in front of page, you
// could opt set a boolean to override that
function setPageTitle(titleName) {
var prefix = "My Site - ";
if ($('section').hasClass('single')) {
Session.set('pageTitle', prefix + titleName);
}
}
As #Kuba Wyrobek pointed out, I needed to use the Template.layout.rendered function.
Here's a snippet that works
Template.postsList.rendered = function(){
Session.set('pageTitle', 'Listing Page')
};
I want an Action event (on="") to trigger when there is a transition to a new Route.
I've seen the list of Action event handlers and closest I could find is attaching the action to the largest HTML element on the page and triggering it with 'Mousemove". This is a terribly flawed away of going about what I want to do.
So just to draw it out.
<div {{action 'displayEitherHtml1or2'}} class="largestDOMelement">
{{#if showHtml1}}
// html 1 inside
{{/if}}
{{#if showHtml2}}
// html 2 inside
{{/if}}
</div>
'/objects' is a list of objects and clicking one leads to 'object/somenumber'. The action should automatically trigger when I enter the 'object/somenumber' page.
UPDATE: I've taken the contents from the previous update and dumped them into my DocRoute, but nothing it being triggered when I transition to 'doc' through {{#link-to 'doc' this.docID}} {{docTitle}}{{/link-to}}
VpcYeoman.DocRoute = Ember.Route.extend(VpcYeoman.Authenticated,{
toggleLetterSwitch: false,
togglePermitSwitch: false,
activate: function () {
var docTemplateID = this.get('docTemplateID');
if ( docTemplateID == 2) {
this.set('toggleLetterSwitch', true);
this.set('togglePermitSwitch', false);
console.log('docTemplateID equals 2');
} else {
this.set('toggleLetterSwitch', false);
this.set('togglePermitSwitch', true);
}
}
});
UPDATE DOS: setDocID is set in the DocsController to 1. Here's the whole thing.
VpcYeoman.DocsController = Ember.ArrayController.extend({
tempDocId: 1,
actions: {
addDoc: function (params) {
var docTitle = this.get('docTitle');
var docTemplateID = 1;
var docTemplateID = this.get('tempDocId');
console.log(this.get('tempDocId'));
var store = this.store;
var current_object = this;
var doc = current_object.store.createRecord('doc', {
docTitle:docTitle,
docTemplateID:docTemplateID
});
doc.save();
return true;
},
setDocId: function (param) {
this.set('tempDocId', param);
console.log(this.get('tempDocId'))
},
}
});
As #fanta commented, it seems like you're looking for the activate hook within your Route. This gets called when you enter the route where you define it. If you want to call it on every transition, you might consider defining a base route for your application and extending that instead of Em.Route:
App.BaseRoute = Em.Route.extend(
activate: function () {
// Do your thing
}
);
App.YourRoutes = App.BaseRoute.extend()
It's possible that there's a more appropriate place/time to do this, but without knowing quite what your action does, this is probably the best guess.
ETA: Looking at your edit, you won't want all your routes to extend App.BaseRoute the way I did it above; you should probably just include that activate hook explicitly in the routes which need it.