Mootools 1.6 Subclass initialize method is not called - javascript

I'm using mootools 1.6.
I based my code on their tutorial but when I try to run it, the initialize function of my subclass is not invoked. Instead, it goes directly to the parent class' initialize function.
I tried breakpointing inside the subclass initialize function but it really doesn't go there. In fact, my additional functions are also undefined. It's like only the functions of the parent class are created. :(
Here's my sample code:
parent.js
var Parent = new Class({
initialize: function(){
alert("parent");
},
...
});
child.js
var Child = new Class ( {
Extends: Parent,
initialize: function () {
this.parent();
alert("child");
},
... some additional functions
});
1.) Note that they are in different js files.
2.) These files are preloaded by cocos2d-js
...
"src/controllers/parent.js",
"src/controllers/child.js",
...

I was able to solve this issue. There's no issue with Mootools. It was how I used it. I'm posting it for people who might encounter the same issue.
I have 3 js files.
parent.js
child.js
orphan.js (calling it orphan hahaha)
These 3 files are added to project.json in that order. I'm not using orphan.js. I thought I already removed it from the list but I was wrong. :(
Inside orphan.js, is a class. This class uses the same name as the class inside child.js. It's empty and is just extending the parent. What happened was, it redefined the object since it's loaded after child.js.
I switched their order to see if it will use child.js declaration instead and indeed, it did. But that's not the solution. I just used it to prove that it was redefined. The solution was to remove that file from source / make sure no classes have the same name.
Whew. false alarm.

Related

How to deal with DOM elements?

I am learning about writing custom JavaScript for my Odoo 10 addons.
I've written the following piece of code:
odoo.define('ioio.io', function(require) {
'use strict'
const e = $('div.o_sub_menu_footer')
console.log('--testing--'.repeat(7))
console.log(e)
// the "Powered by Odoo" down the secondary menu
e.remove()
})
The code is well loaded and I can see my testing string in the console.
However when this code is being loaded before the target div, so e empty/not yet filled and thus its content is not removed.
Doing it manually from the console works.
My question is what is the right way to do that? And how to know exactly when the code gets executed?
You can
put your html code before the script tag in your file
use jQuery $(document).ready(...);
Place your script at the bottom of the <body> tag to make sure the DOM renders before trying to manipulate it.
This is an Odoo specific question, so you should use the Odoo standard way, which is via its base JS class. That class contains a ready() method which does exactly what you need.
In your case, to use that function, you need to require the class first. Then you can use ready().
Updating your code, it should look like this:
odoo.define('ioio.io', function(require) {
'use strict'
// require base class
var base = require('web_editor.base');
//use its ready method
base.ready().done(function () {
// put all the code you want to get loaded
// once the DOM is loaded within this block
const e = $('div.o_sub_menu_footer')
console.log('--testing--'.repeat(7))
console.log(e)
// the "Powered by Odoo" down the secondary menu
e.remove()
});
})
While your accepted answer leads to the same outcome, you might want to update it to this one since this is the Odoo way. It's generally advised to work within the Odoo framework as much as possible and customise only if really needed. (Though it can be tough to learn what features Odoo already provides because of its poor documentation.)

TypeScript - How to get an HTML element like using dollar sign ($) in Javascript

I have the following javascript code in my page that get an element with the class ".parallax" and calls the javascript method "parallax()".
Obviously, I need to do this to make the parallax effect to work.
$('.parallax').parallax();
However, once I'm using my HTML elements in the component template in TypeScript file, I need to call it from the TS file.
So how can I get this element by its class name and call the javascript method in Typescript file?
Obs.: I already tried to do this:
var element = <HTMLElement> document.getElementsByClassName('parallax')[1];
element.parallax();
But the compiler doesn't recognize the method "parallax()", warning me this:
TS2339: Property 'parallax' does not exist on type HTMLElement
$('.parallax').parallax();
If parallax is a JQuery function you need parallax.d.ts:
interface JQuery {
parallax: any;
}
And I am pretty sure this is what you want.
Thank you for your help, #basarat!
I followed your tips, but I needed more information to make it work!
My initial problem was to use the $ (dollar) sign, and I solved it by adding this:
import * as $ from 'jquery';
The import above is the right answer to my main question here. However, it was not enough to make the external Javascript function .parallax() to work.
I will show below what I did to make ot work whether someone also needs this answer.
I followed some tips from this StackOverflow answer.
Like basarat said, I created a file named parallax.d.ts, but with the following interface:
interface JQuery {
parallax():JQuery;
}
Then referenced both parallax and jquery files to my component landingPage.view.ts file:
///<reference path="../../../typings/browser/ambient/jquery/index.d.ts"/>
///<reference path="../../shared/parallax.d.ts"/>
and then edited my component class to this:
export class AppLandingPage implements AfterViewInit {
static landingPageInitialized = false;
constructor(private el:ElementRef) {
}
ngAfterViewInit() {
if(!AppLandingPage.landingPageInitialized) {
jQuery(this.el.nativeElement)
.find('.parallax')
.parallax();
AppLandingPage.landingPageInitialized = true;
}
};
}
Now, by my understanding, the constructor is referencing the component through the el variable, I use this element in jQuery, find the components with the ".parallax" class, and call the function parallax() to make the parallax framework in JS to run.
I'm not sure if I'm explaining everything as it is, but now it works! Hehe
Thank you again for all your help!

Converse.js render into a container

Is it possible to configure Converse.js to render it's boxes into custom div containers instead of adding them to the body of the page?
Yes, you can do this by writing a converse.js plugin in which you override the insertIntoPage method of ChatBoxView.
Refer to the plugin documentation I linked to above. In short, it would look something like this:
// The following line registers your plugin.
converse_api.plugins.add('myplugin', {
overrides: {
// If you want to override some function or a Backbone model or
// view defined inside converse, then you do that under this
// "overrides" namespace.
ChatBoxView: {
insertIntoPage: function (type, status_message, jid) {
// XXX Your custom code comes here.
// The standard code looks as follows:
this.$el.insertAfter(converse.chatboxviews.get("controlbox).$el);
return this;
}
},
}
UPDATE: Since recent versions of converse.js, the method to override is instead _ensureElement and not insertIntoPage.

How to Add Global/Public Variables to grunt-contrib-uglify Output

Okay, so I am way new to Grunt and Node.js. I am building a site, and decided that the 'main.js' file was getting way too big. So, I split it up, and I am now trying to use Grunt to piece all of these JS files back together.
The issue that I have is that I need to make some global variables available to all of the various functions in all of these JS files. To be more specific, every page on our site is identified via an id in the body tag:
<body id="home">
Many of these JS files contain if statements that ensure certain functions only run if the appropriate page is loaded. For example:
if (page == 'home') {
var title = "Home Page"
$('.page-title').text(title);
}
Notice the page variable? That guy is the one that I need to make available to all of these files (after grunt-contrib-uglify merges them together). So, I figured I'd assign a new "unique" variable name, and make it global.
I noticed that grunt-contrib-uglify has a 'wrap' option listed in its documentation. However, no examples are given as to how to use it.
Can anyone tell me:
- How to use the 'wrap' option in 'grunt-contrib-uglify'
- If this is the right grunt plugin for what I am trying to do?
One idea I had (as a last resort) is to create a before.js and after.js and put the beginning and end (respectively) of what I wish to wrap around the other files in each. But, I think the 'wrap' option is what I need, yes?
UPDATE: Here is a link to my "merged" JS file:
main.js
And a link to my Gruntfile:
Gruntfile.js
I have been having the same problem an searching for a solution. But I think I found an answer.
Use this in your gruntfile:
uglify: {
options: {
wrap: true
}
}
The documentation for the wrap property indicates that the variables will be made available in a global variable, and looking at the generated code that does seem to to be the case. Passing a string value to the parameter does seem to create a global variable with that name.
However, wrap: true seems to make all objects and properties available in the global scope. So instead of globals.page.title (which I can't get to work, anyway), you can just use page.title. Much, much easier and simpler.
If this suits your purposes, I'd recommend doing this instead.
Ok this one is tricky, I have been stucked for a while...
Way you do this with grunt-contrib-uglify for frontend JS
create multiple files like
SomeClass.js
OtherClass.js
main.js
and use some module (grunt-file-dependencies or grunt-contrib-concat) and setup it to concat your files. Then setup uglify in your Gruntfile.js like
...
uglify: {
options: {
wrap: "myPublicObject",
...
},
In file (main.js for example) exports variable has to be assigned, the entire file might look like this:
var otherClassInst = new OtherClass();
var someClassInst = new SomeClass();
exports = otherClassInst;
Now what it exactly does
Uglify will pick superior context (this) and define property on it named myPublicObject. Then it wrap your sourcecode with function and create exports variable here (DO NOT DECLARE var exports anywhere). At the end it will assign what you exported to that property. If you dont assign anything (you dont use exports =) inital value is {}, so the property with void object exists anyway.
To make this super-clear,
if you put your code into page like <script src="myminifiedfile.min.js"></script>, then superior context is window =>
window.myPublicObject is instance of OtherClass while window.someClassInst, window.SomeClass and window.OtherClass are undefined.
this is unlikely, but if you just copy content of minified result and wrap it with different function, object you exported will be visible only via this["myPublicObject"] => uglify wrap doesn't make things globaly accessible, it makes them accessible in superior context.

Ext.Template is not defined

I'm having trouble preparing my application for deployment. I'm using ext-dev.js and have a compnent with the following:
Ext.define(myNameSpace.myComponentName, {
requires: ['Ext.XTemplate'],
tpl: new Ext.XTemplate('someTemplate')
})
On application startup it gives an
Ext.XTemplate is not a constructor
Do you have a solution for this?
You cannot define Ext.XTemplate inline because it hasn't been retrieved from the server yet by the Ext.Loader which handles loading of dependencies. There are two solutions:
// If you really want to add it to the prototype, but adding objects to the
// prototype is usually a bad idea since they are shared by all instances
// In this case, it may be ok, since there isn't much you can change about a
// template after you create it
Ext.define('myNameSpace.myComponentName', {
requires: ['Ext.XTemplate'],
}, function() {
// This callback is for when all the dependencies are loaded
myNameSpace.myComponentName.prototype.tpl = new Ext.XTemplate('someTemplate')
});
// Or just define it in initComponent, since you shouldn't instantiate it
// until after Ext.onReady is called (which means all dependencies are loaded)
Ext.define('myNameSpace.myComponentName', {
requires: ['Ext.XTemplate'],
initComponent: function() {
this.tpl = new Ext.XTemplate('someTemplate');
this.callParent();
}
});
UPDATE I actually forgot to list another possibility that may work, that is, don't use new, use Ext.create('Ext.XTemplate', args)'. The problem with Ext.create is that it will block until Ext.XTemplate (and dependencies) is loaded. I would still go with one of two approaches mentioned at the top

Categories

Resources