What is the right way to extend a main controller within a meteor package?
This is my case, the main controller is inside the app.js file, located in
both/controllers/app.js
The content is
AppController = RouteController.extend({
layoutTemplate: 'appLayout'
});
Inside my-package folder, I've created a router.js file
packages/my-package/lib/router.js
Below the content of the file, here came the question: why if I move the DashboardController declaration outside the Meteor.startup() function, it doesn't work?
DashboardController = AppController.extend({}); // here doesn't work
Meteor.startup(function () {
Router.route('/dashboard', {
controller: DashboardController,
name: 'dashboard'
});
The output is
ReferenceError: AppController is not defined
why if I move the DashboardController declaration outside the
Meteor.startup() function, it doesn't work?
That's because of the load order of Meteor build process : every package JS files are loaded according to dependencies between them and only after the actual application code is executed (which makes sense).
The solution is to move your DashboardController inside a Meteor.startup block so that it's executed after the application code had a chance to define AppController.
You could also move your AppController inside an application-core or application-controllers local package of yours and depend on that package.
Related
Meteor says when you write some javascript in a JS file, every file automatically has access to it everywhere in the app, but when I write a function in a a separate file like that, I just get a console error saying that function could not be found when I call it in html. The only way I can get it to work is by writing the JS in the html file but I want to keep the languages separate. Any idea on what the problem is?
code:
html in one file:
<button onclick="dylan()"></button>
js in another file:
function dylan(){
console.log("hello");
}
the problem is, when I click the button, it says dylan is not a function.
Meteor docs do not spell this out but every individual javascript file is wrapped into a closure:
(function() { //the file content // })()
so all functions in a given file have their own scope.
Functions defined in a js file in Meteor normally only have file scope - that is, any object in that file can refer to them.
If you want to define a global function, create a global variable:
dylan = function(){
...
}
Note the absence of let or var which would restrict the function to file scope.
Now you can use this global in your onclick handler.
Note however, that normally in Meteor, you would define an event handler at the template level, ex:
Template.myTemplate.events({
'click button'(){
...your code here
}
});
As opposed to referring to event handlers in your html directly.
The purpose of using Meteor is not met if you do not harness the wonderfull features such as
Template.X.events({});,
Template.X.helpers({}); and also
Template.registerHelpers({});
You can write your desired code in below way:
Template.template_name.events({
'click .button_class' : function() {
console.log("Hello");
}
});
//HTML
<button class="button_class"></button>
If that click event has to be used in more than 1 HTML then you can use registerHelper methods than template click events.
Template.registerHelpers('dylan' : function() {
console.log("Hello");
});
//html
<button onclick="dylan"></button>
To access dylan(), you must first load the script file that contains that function into the html document.
You can do this by adding <script src="myfile.js"></script> anywhere before the button. (replace myfile with the name of your script)
Once loaded, <button onClick="dylan()"></button> will work!
I have an Adobe Illustrator action file (.aia) that I'd like to load in the extension builder environment via .js or .jsx. I noticed that there is app.loadAction() - but I can't get the operations to work. If I have the action file stored in my root folder, how do I get the actions to load in Illustrator?
Below is the setup I got working. This extension uses HTML panels, with a button click, we load an action into Illustrator. The button click triggers the JS function below which then calls to the JSX script. The .aia file is stored in the root folder, ./assets
JS function:
function getActionFile() {
var extensionRoot = csInterface.getSystemPath(SystemPath.EXTENSION) + "/assets/Utility.aia"; //exported aia file
csInterface.evalScript('loadActions('+JSON.stringify(extensionRoot)+')');
}
JSX function:
function loadActions(f){
var scriptFile = File(f);
app.loadAction(scriptFile)
}
I'm currently developing a Meteor application where I use the video.js-Library.
I have the following template:
template(name='foo')
.video.embed-responsive.embed-responsive-16by9
with richMediaContent
video#video.video-js.vjs-default-skin.vjs-big-play-centered(controls='' preload='auto')
source(src='{{video.videoUrl}}' type='video/mp4')
p.vjs-no-js {{i18n 'videoTagNotSupported'}}
Initializing the video.js-Library after the template is rendered works fine.
Template.foo.onRendered ->
videojs document.getElementsByClassName('video-js')[0], {}
But the videojs-Library is not reinitialized if the same template is rendered with a different video (with a different richMediaContent).
I've already tried to move the video-Part in an own template and included it in the foo-Template so that the onRendered-Call should get called every time a new video is loaded. But this doesn't seem to work.
Do you have any idea how I can reinitialize the library if the video changes?
Thanks in advance!
New answer
Indeed, when your route changes but uses the same template, the said template does not get rendered again, therefore your js plugin call will not trigger a second time. What you can do instead is call your js plugin in an onAfterAction call, within your route definition:
Router.route('/video/:_id', {
name: 'video_page',
template: 'foo',
// ...
onAfterAction: function () {
videojs document.getElementsByClassName('video-js')[0], {}
}
});
Previous answer
I think you are looking for the almighty this.autorun. At the end of your onRendered function, it should look like this (I type it in pure javascript)
this.autorun(function () {
var video = Session.get("video"); // reactive data
videojs document.getElementsByClassName('video-js')[0], {}
});
The idea is that the first line must include, within the autorun function, a way to get your reactive data. In that case, I use the Session which is reactive. Collections are also reactive, so another way would be something like Videos.findOne();. This will depend on how you get that video element.
What this does is that any time the reactive data changes, the callback for this.autorun will run again, and your video plugin will be reset.
I'm trying to use document.querySelector("body") but i'm not getting any html elements back.
Why is that, the call to my script is inside meteor.startup?
I'm using iron router for my routing...
if(Meteor.isClient){
Meteor.startup(function(){
myScript()
})
}
Meteor.startup can fire only after DOMContentLoaded event. But IronRouter will probably render the content after that later.
Try either using IronRouter's onAfterAction hook or template's rendered callback
I ended up doing this:
Template.masterLayout.rendered = function(){
myscript = myScriptJS()
}
This calls myScriptJS() in the .rendered method of my iron router layout. myScriptJS is executed and assigned to a global variable (myscript) because myScriptJS is a module pattern that is returning an object to it's namespace.
Now i can use this code everywhere:
myscript.counter()
I have some post-processing that I have to do on a list of HTML elements whenever they are updated from the backend. Is there some event (like, onRender) that I can listen to on the template to facilitate this?
For Meteor starting from 0.4.0 preview, you can use Template.myTemplate.rendered for this.
Template.myTemplate.rendered = function() {
console.log('Template has been (re-)rendered');
}
See also this conversation: Callback after the DOM was updated in Meteor.js
I used the technique to set Bootstrap tooltip popup events in the DOM after template (re)rendering in my CoffeeScript port of the Leaderboard example.
This in the template:
{{enable_tooltips}}
Calls this (CoffeeScript) template property method on the client:
enable_tooltips: ->
# Update tooltips after the template has rendered.
Meteor.defer -> $('[rel=tooltip]').tooltip()
''
Template.userDashboard.onRendered(function() {
// Initialize animate panel function
$('.animate-panel').animatePanel();
}
renamed in Meteor 1.0.4 from rendered to onRendered. Also it now takes a callback function.
http://docs.meteor.com/#/full/template_onRendered