I have a category dropdown(in parent js) whose subcategory fills on parent page load as well on dropdown change . subcategory will fill from child js method .I have to create child js instance twice . on page load and on dropdown down change.
I dont want to create object in document.ready or as global variable
where should i create child class object exactly so that it can be used all over ?
problem is that jquery not letting me call
$.getScript('../Reports/assets/js/BookingReports.js'
twice as it send error that child class name(BookingReports) identifier as already created .
class ReportsInterface extends ReportBase {
constructor() {
super();
this.fillSubCategory;
}
init() {
this.Categories();
}
Categories() {
//fill category
this.FillSubCategory();
}
FillSubCategory() {
if(!this.fillSubCategory) {
$.getScript(
'../Reports/assets/js/BookingReports.js',
function() {
this.fillSubCategory=new FillSubCategory("1");
obj.GetSubCategory();
}
)
}
}
}
$(document).ready(function() {
$("#ddlcategory").on('change', function() {
(new ReportsInterface()).showReportBooking();
})
})
i also tried to save object in parent class property but .cannot use it as object later on. how can I call child class method twice without creating any global variable ?
If you are using ES6, I would recommend not using JQuery to import separate files but rather using the ES6 import/export syntax.
I imagine the issue is that since $.getScript makes an http request to redownload the script file, it is actually running the script file twice (one for each download); in the second download, it will run into the naming conflict. ES6 import/exports would solve this issue for you, preventing BookingReport from being redefined.
You should be aware of a couple of things however:
(1) Using your JQuery setup, you get the benefit of lazy loading. To get the same in ES6, you'd have to use the slightly more complicated dynamic imports (see that same link above) -- for this app, however, it doesn't really look like you'd need that.
(2) You might want to familiarize yourself with a bundler like Webpack as this will do ahead-of-time importing and leave you with a single file to download rather than having to ping-pong back and forth from the server as you try to download all of the modularized files.
Related
I need a way to make the parent object for any "known" function call inside a certain scope a certain object, just like the window object, for example:
in javascript, we don't have to write window.document.querySelector we can write document.querySelector directly, I need to implement the same idea in my application but I'm unable to figure out the algorithm to make it?
my application works the following:
the programmer (I am programming a library) will pass an object inside a method called "move", the "move" method will take this object which will look like the following:
DOMMAP:{
A:{
onfirstload(){
override() // I want this one to be like window.something, I want this to be automatically myLibrary.override() without forcing the user of my library to write manually myLibrary.override()
}
}
}
the myLibrary is class that have methods, the "override" method is one of the "known" methods:
class myLibrary{
override(){
//do something
}
move(DOMMAP){
//traverse the DOMMAP object... do some magic
}
}
I want this one to be like window.something, I want this to be automatically myLibrary.override() without forcing the user of my library to write manually myLibrary.override()
I want to make this thing (the global object from the perspective of the inner functions to be automatically set to myLibrary) inside the scope of the property "onfirstload" method.
We used to have with but it's not recommended.
What I can suggest is you use this and bind. You can have the function in your object like so.
{
onfirstload(){
this.override()
}
}
Then call bind in your move method.
class myLibrary{
override(){
//do something
}
move(DOMMAP){
DOMMAP.onfirstload.bind(this)()
}
}
Doing a bind changes the context of this to the class instance.
You can create a separate .js file in which you can create the class and import its methods as a VAR type.
And then import this file in the root file. It would be available to all the files.
I use the Universal style for my QtQuick app and I want to provide a ColorDialog for adjusting the accent color.
I have something like this:
ColorDialog {
id: accChooser
title: "Please choose a color"
onAccepted: {
setGlobalAccentColor(accChooser.color)
}
}
*Note that I cannot simply write Universal.accent=... inside a child item because it has no effect on the parent.See this.
and this function:
function setGlobalAccentColor(accentColor){
Universal.accent = accentColor
}
It works when the function setGlobalAccentColor is defined within the same QML file as accChooser,but if I define that function inside an external JS file (say helpers.js) and import it via:
import "helpers.js" as JSHelpers
and use it this way:
ColorDialog{
...
JSHelpers.setGlobalAccentColor(colorDialog.color)
...
}
it doesn't work.There's no specific error or warning message in the output of the app.
Thanks.
May be it is required to import the universal style in the javascript file.
The documentation universal style says below (look in dependency section)
The Universal style must be separately imported to gain access to the
attributes that are specific to the Universal style
You can try importing as said below into your javascript (helpers.js) file.
.import QtQuick.Controls.Universal 2.12 as JsUniversal
And then try accessing (like example: JsUniversal.accent..).
Note that I cannot simply write Universal.accent=... inside a child item because it has no effect on the parent.See this.
While setting it to the child won't affect your whole application, you can set it directly to the whole window.
Window.window.Universal.accent = accentColor;
Universal is an attached object, you can attach it to an abitrary object, not just the current one, by doing <object>.<AttachingType>.
We attach it to the parent window by accessing the window via another attached property: Window.window.
I am trying to require in some classes in Node, but I require them in through a single file which holds an object of all the individual requires. Like so -
File: /classes/controller.js
module.exports = class Controller {}
File: /classes/model.js
module.exports = class Model {}
File: /classes/classes.js
module.exports = {
Controller: require('./controller.js'),
Model: require('./model.js')
}
Then in app.js
const classes = require('./classes/classes.js');
....code.....
....more code.....
const someController = new classes['Controller'];
The thing is, this works just fine - but only for the first file that requires in the 'classes' variable. Any subsequent files that need to also require 'classes' in, ends up holding only an empty object inside of the 'classes' variable (and no, the actual variable name does not matter, as I tried using a different variable name in the second file but it still wound up storing an empty object). For instance, I often need my Controller to implement a Model class.
So once app.js calls controller.js, inside of that -
File: /classes/controller.js
const classes = require('./classes.js');
module.exports = class Controller {
constructor(var) {}
someMethod() {
....code....
const someModel = classes['Model'];
}
}
I can call a 'console.log(classes)', and it will print out '{}', but again this is only if it is done inside of 'controller.js' and only after being called from inside of 'app.js'. It will print out all of the classes as expected if the 'console.log()' is done either inside of 'app.js', or if 'controller.js' is called directly instead of through 'app.js'. Which is how I know where/how the error is occurring. The specific error being thrown is -
classes.Model is not a constructor
So that is where my question/problem comes in, because as I said I have called other objects in multiple files without ever running into this problem. So it must have something to do with how classes are implemented, correct? And although I do not understand the specifics of how it works, I roughly know that when a file is required in, in Node, after that it uses that same reference for any subsequent files - correct? So I was thinking it must somehow be the interplay of those two things, but I have no idea after that fact nor if I am even correct in assuming that is the problem.
You have a circular dependency of require() statements. This causes one of the require() to just return an empty object. You can't do that.
Inside of controller.js, you have require('./classes.js');.
Inside of classes.js, you have require('./controller.js').
So, each refers to the other which is what causes the circular dependency.
You will need to restructure the way code is laid out into files so you don't have this. Sometimes, the simplest fix is to just combine a couple functions into one file rather than having them all in separate files that are vulnerable to this issue. I don't quite understand your overall design to know what best to suggest in this case.
If nobody else besides controller.js is really going to use classes.js, then you can just move that code into controller.js (where you don't need to require in controller.js any more).
I have a js file in my Angular application, data.js . This js file has some variables declared in it, something like below.
var data = 'test'
Now I have to access these variables and their values in my component (app.component.ts).
I read some where that declaring them as exports make them into modules and those can be accessed anywhere, But I'm not sure how this can be done.
This is the structure of my application. I have data.js in assets->js folder.I need to modify the variable value in app.component.ts.
I'm very new to Angular. Is this even possible?
With the file in your assets, I am guessing you are declaring it on the window. You will need the include the script in your index.html, and then access it on the window within your component via window.data. This is not really the recommended way of doing this unless your use case dictates it. The module approach you mentioned is preferred.
Next to your app.component.ts, create a file called data.ts, with:
export let data: string = 'data';
In your app.component.ts, import it using:
import { data } from './data.ts';
If you plan to not mutate that data, consider using the const keyword instead (in data.ts).
Directory structure
/app.component.ts
/data.ts
/...
Edit: Show Global Approach
You will need to include your script outside of the context of the Angular application. If you bootstrapped your application using the Angular CLI, you can add a reference to it in the cli configuration file. See this documentation on the topic.
That file will be included and will be available for access within your component on the window. The tricky part comes with typing and the Window. And example may look like this.
class AppComponent extends Component {
private data: string;
constructor() {
// Explicitly cast window as an any type. Would be better to type this, but this should work for you.
this.data = (<any>window).data;
}
}
(referrring to https://stackoverflow.com/a/42682160)
first you have to include the script into your src/index.html like
< script src="/assets/js/data.js">< /script>
important is that the above statement is placed before your angular root component tags
(< root-component>< /root-component> or < ion-app>< /ion-app> or something like that)
then you can simply write (for example inside app.component.ts ngOnInit function)
let varFromJsFile = window["data"] // varFromJsFile = 'test'
You want the variable to be a member of a Component class, not just a variable declared anywhere within a module.
If this doesn't make sense right away, you need to look more carefully at some basic Angular code samples.
Also, as long as you're using Angular and therefore TypeScript, it's better the declare variables using let or const.
Im not really sure if Im understanding correctly the way observables work and how to get references from mounted tags. I have a component. Within this component we have a component and a component. The purpose is to avoid coupling between components. Because of that, I would like that my search component triggers an event when a search is done(a button is clicked). This event should be caught by the component which will filter the collection data based on the search.
The index.html file load the tag by using:
index.html
riot.mount(".content", "page", null);
The page is defined as follow:
page.js
<page>
<!-- Search tag controls -->
<search id="searchTag"></search>
<!-- Collection data to display -->
<collection id="collectionTag"></collection>
</page>
The component script is briefly defined like:
search.js
var self = this;
riot.observable(self);
<!-- This function is called when the user click on the button. -->
self.filtering = function()
{
<!-- We get data from inputs -->
var info = Getting data from inputs;
<!-- Trigger the event hoping that someone will observe it -->
self.trigger("filterEvent", info);
}
How can I make the component observe for that event?
To me it seems that I should be able to get references from search tag and collection tag in the page.js. By doing so I could connect the events like follow:
searchComponent = riot.mount('search');
collectionComponent = riot.mount('collection');
searchComponent.on('filterEvent', function()
{
<!-- Trigger function to filter collection data -->
collectionComponent.trigger('filterData');
});
Right now I cannot make it work like that.
At the point of execution, searchComponent and collectionComponent are not defined.
I tried also getting references of these component by using this.searchTag and this.collectionTag instead of mounting them but at the time the code is executed, the components have not been mounted and so I dont get a reference to them.
Any ideas to make it work?
Inspired by the answer given by #gius, this is now my preferred method for sending events in RiotJS from one tag to another.. and it is great to work with!
The difference from #gius approach being that, if you use a lot of nested tags, passing a shared Observable to each tag falls short, because you would need to pass it again and again to each child tag (or call up from the child tags with messy this.parent calls).
Defining a simple Mixin, like this (below), that simply defines an Observable, means that you can now share that in any tag you want.
var SharedMixin = {
observable: riot.observable()
};
Add this line to your tags..
this.mixin(SharedMixin);
And now, any tag that contains the above line can fire events like..
this.observable.trigger('event_of_mine');
..or receive events like this..
this.observable.on('event_of_mine',doSomeStuff());
See my working jsfiddle here http://jsfiddle.net/3b32yqb1/5/ .
Try to pass a shared observable to both tags.
var sharedObservable = riot.observable();
riot.mount('search', {observable: sharedObservable}); // the second argument will be used as opts
riot.mount('collection', {observable: sharedObservable});
And then in the tags, just use it:
this.opts.observable.trigger('myEvent');
this.opts.observable.on('myEvent', function() { ... });
EDIT:
Or even better, since your search and collection tags are child tags of another riot tag (page) (and thus you also don't need to mount them manually), you can use the parent as the shared observable. So just trigger or handle events in your child tags like this:
this.parent.trigger('myEvent');
this.parent.on('myEvent', function() { ... });
Firstly I do not understand your file structure !
In your place I would change filenames :
page.js --> page.tag
search.js --> search.tag
And i dont see your search tag in search.js code.
So I dont see your Collection tag file ...
Are you sure that this one use this code ?
riot.observable({self|this});
Because it's him who will receive an Event.
For me when I use Riot.js(2.2.2) in my browser, if I use
searchComponent = riot.mount('search');
searchComponent will be undefined
But with this code you can save your monted tag reference :
var searchComponent ={};
riot.compile(function() {
searchComponent = riot.mount('search')[0];
});
Another option is to use global observables, which is probably not always best practice. We use Riot's built in conditionals to mount tags when certain conditions are met rather than directly mounting them via JS. This means tags are independent of each other.
For example, a single observable could be used to manage all communication. This isn't a useful example on its own, it's just to demonstrate a technique.
For example, in a plain JS file such as main.js:
var myApp = riot.observable();
One tag file may trigger an update.
var self = this;
message = self.message;
myApp.trigger('NewMessage', message);
Any number of other tag files can listen for an update:
myApp.on('NewMessage', function(message) {
// Do something with the new message "message"
console.log('Message received: ' + message);
});
Maybe overkill but simple. let riot self observable
riot.observable(riot);
So you can use
riot.on('someEvent', () => {
// doing something
});
in a tag, and
riot.trigger('someEvent');
in another.
It's not good to use global variable, but use an already exists one maybe acceptable.