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.
Related
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 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.
QUESTION
How can I pass a variable containing a function from a pug file (I don't think it's specific to .pug files) to a react component?
route.js
const login = () => { ... 'log the user in here' ... };
app.get('/test', (req,res) => {
res.render('page.pug', {varName: {list_test: ['hello', 'goodye'], login_func: login}});
page.pug
body
script.
var data = !{JSON.stringify(varName)}
file.jsx
// Imagine this being called from a react component's constructor
console.log(data);
(file.jsx) Console output: {list_test: ['hello, 'goodye']}
Notice that the function 'login' (as well as its associated key 'login_func') has disappeared from the variable?!
The answers to the linked questions outlined below doesn't work when the variable contains functions, however it does work for strings, numbers, lists, and objects. Therefore, this is not a duplicate of any of the following:
Pass a param from pug to JSX
Passing a variable from a jade file to a React Component
It kinda makes sense (Me considering what the issue might be - I might be wrong)
When you stringify the JSON object, I suppose it would be troublesome to turn a string into a function:
function sayHello() { console.log('Hello') }
var string = "sayHello"
Now to somehow turn that string into a non string again and point to the sayHello function would cause problems - is what I think.
Use environmental variables
pug -> environment variable -> react
The Create React App build allows for environment variables to be used within the app. To add an environment variable create a .env file in the root of your project, then add the appropriate variables and prefix the variable name with REACT_APP_. For example:
REACT_APP_MYVAR = "someString"
In the app these variables can be accessed within your components with {process.env.REACT_APP_MYVAR}, or within the HTML with %REACT_APP_MYVAR%.
So in order to send pass a variable from pug to react all you would have to do would simply be to first pass your variable to the environment variable and then have your react file access that environment variable.
I am generating an angularJS project with yeoman. I call the generator with an argument and I get it from my main generator's script (index.js) by doing:
this.argument('name', { type: String });
I can use this parameter inside this same index.js by using:
this.options.name
Question: I want to use this same this.options.name inside my template, so that i can give its value to a variable. How can I do it?
To access a yeoman variable from Node.js, I did the following:
I renamed the file connections.js from sails, renamed it to _connections.js and placed it at the same level than sails folder inside the folder "templates" from yeoman's generator. Leaving it like this:
> yeomanGeneratorFolder
> |-app
> |-index.js
> |-templates
> |-sails
> |-_connections.js
> |- ....
On the Generator's index.js. I created a function to write on a js file the data I needed. I sent a JSON object inside the copyTpl() function which contains the data I will need in the new file:
connections() {
this.fs.copyTpl(this.templatePath('_connections.js'), this.destinationPath('./config/connections.js'),
{
dbName: this.item.dbName
});
}
In _connections.js I wrote:
database: '<%=dbName%>' //optional
Notice dbName is the key I gave to the JSON I sent inside the copyTpl() function in index.js.
Define an angular constant and set it to this value. Then inside the controller associated to this view, just inject this constant.
myApp.constant('YEOMAN_NAME', MYVALUE);
Then just inject your constant inside the controller associated to your view, associate this constant to a scope variable and use it inside your template.
Now the "hardest" part is how to get this value inside the angular environment.
I don't know what is your index.js, I suppose that is only the main script associated to your page.
In this case, if you do inside the main script something like
this.myVariable = 'myValue';
You are actually creating a new attribute to the window object (if you are not doing that inside some function)
So what you could do is to associate this variable to a window parameter, and try to be most specific as possible so you are not on risk to override something else in the window, like:
window.myYeomanName = this.options.name;
Then you can define your constant inside angular everywhere just doing:
myApp.constant('YEOMAN_NAME', window.myYeomanName);