I am trying to call one of the function in from .js file in angular whenever a route change happen.
This is my code in the javascript file and I need to call need to call the appData function in angular.
The console.logs for console.log(parsedJsonResponse); and console.log(appData) works fine and I am getting the JSON response.
window.dataLayer = (function () {
var dataCall = function () {
return new Promise((resolve, reject) => {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
resolve(this.responseText);
} else {
console.log(this.status + '.....' + this.statusText)
}
}
};
xhttp.open("GET", "http://localhost:4200/assets/sample.json", true);
xhttp.send();
})
}
dataCall().then((CallResponse) => {
getData(CallResponse)
});
window.addEventListener("load", function (event) {
appData();
})
var getData = function (cData) {
jsonResponse = cData.replace(/'/g, '"');
parsedJsonResponse = JSON.parse(this.jsonResponse);
var appData = parsedJsonResponse['content']['copy$$' + applicationContent];
console.log(parsedJsonResponse);
}
I am calling appData function in
var appData = function (applicationContent) {
var appData = parsedJsonResponse['content']['copy$$' + applicationContent];
console.log(appData)
}
return {
appData: appData,
dataCall: dataCall
}
}())
This is my code in angular calling the function.
When calling this function in angular I'm getting ReferenceError: parsedJsonResponse is not defined.
constructor(private router:Router) {}
ngOnInit(){
this.router.events
.filter(event => event instanceof NavigationStart)
.subscribe((event: NavigationStart) => {
dataLayer.appData();
})
};
What is going wrong? Thanks.
parsedJsonResponse variable should be declared outside all functions if you're going to use it in different functions. Otherwise parsedJsonResponse is private to getData function.
window.dataLayer = (function () {
var parsedJsonResponse;
// ...rest
Next you need to remove the function call inside window load event. appData() is getting called in window load but the data is still fetching and parsedJsonResponse has no content.
window.addEventListener("load", function (event) {
// appData();
})
In getData function remove this since jsonResponse is a private variable.
parsedJsonResponse = JSON.parse(jsonResponse);
I hope this will help.
EDIT:
Anyway I don't encourage using external js files. Try to use a service inside your Angular app.
UPDATE:
You are not passing the parameter in dataLayer.appData().
You are not handling the exceptions properly in the API request.
Try to declare parsedJsonResponse variable inside of a dataLayer function:
window.dataLayer = (function () {
var parsedJsonResponse;
/* rest of your code */
EDIT
The problem why this is happening, because your variable parsedJsonResponse gets its value, when ajax response comes from the server. It means, that it depends on async action. What you can do, is wait for response in promise. My suggestion is to keep that promise in new variable getAsyncData:
var getAsyncData = dataCall().then((CallResponse) => {
getData(CallResponse)
});
also don't forget to add that variable into return object:
return {
appData: appData,
dataCall: dataCall,
getAsyncData: getAsyncData
}
and you can use it in your angular app like so:
dataLayer.getAsyncData.then(() => {
dataLayer.appData();
});
One more thing I've noticed, that you are using applicationContent in getData function, but it haven't been initialized in your function dataLayer. The only usage on that variable in appData:
var appData = function (applicationContent) {
You should consider also initializing that variable on top of your function.
window.dataLayer = (function() {
var parsedJsonResponse;
var applicationContent;
/* rest of your code */
Here is the code, which I've made on top of your's with slight changes(here I sending response to jsonplaceholder server, so parsing that response is different, and also I've removed load event listener:
https://jsbin.com/birofufade/edit?html,js,console,output
Related
I'm only learning how to work with the modules in JavaScript, so I have three separate .js files: main, listener and fileHandler
Simply this is a program that for every selected or dropped file(image) from computer gets appended to the page. Functions are working when I drag and drop files to the page, but when I select them through inputBox button files even files are stored in inputBox.files, they are not getting appended to the page.
var uploader = {};
uploader.init = function () {
this.inputBox = document.getElementById('uploadButton');
this.dropbox = document.getElementById('dropbox');
this.listener();
}
and listener method as:
probably I'm calling 'change' event wrongly here, that files are not appended.
uploader.listener = function () {
uploader.inputBox.addEventListener('change', uploader.fileHandler.addFiles(uploader.inputBox.files));
this.dropbox.addEventListener('drop', this.fileHandler.drop.bind(this));
}
one another constructor is:
uploader.fileHandler = new function () {
var uploadHandler = function () {...}
this.addFiles = function (files) {
Object.keys(files).forEach(function (key) {
var file = files[key];
uploadHandler(files[key]);
});
};
this.drop = function (event) {
event.stopPropagation();
event.preventDefault();
var files = event.dataTransfer.files;
this.fileHandler.addFiles(files);
};
}
EDIT
I see another issue. When you do this:
uploader.inputBox.addEventListener('change', uploader.fileHandler.addFiles(uploader.inputBox.files));
You are calling uploader.fileHandler.addFiles(uploader.inputBox.files) immediately and passing it's return value to .addEventListener(). Probably what you want instead is this:
uploader.inputBox.addEventListener('change', function() {
uploader.fileHandler.addFiles(uploader.inputBox.files)
});
Here you are passing an anonymous function reference which can be called later by the event handler.
This construct:
uploader.fileHandler = new function () {
this.addFiles = function (files) {
Object.keys(files).forEach(function (key) {
var file = files[key];
uploadHandler(files[key]);
});
};
}
only assigns a function to uploader.fileHandler. It does not define uploader.fileHandler.addFiles until you actually call that function (which you do not show).
I don't know why you're trying to nest your function definitions (that usually just causes more complexity than benefit in Javascript), but if you really wanted to define them that way, you could do this:
uploader.fileHandler = {
addFiles: function (files) {
Object.keys(files).forEach(function (key) {
var file = files[key];
uploadHandler(files[key]);
});
},
drop: function(...) {...}
};
This would then define both of these functions:
uploader.fileHandler.addFiles()
uploader.fileHandler.drop()
In the wapp.js I have the following class in JavaScript:
function Wapp() {
this.page = function($page_name) {
this.onLoad = function($response) {
}
}
this.navigate = {
changePage: function(link) {
// Ajax request to load the page
$.post(link, {}, function(response) {
// Code to display the page
});
}
}
}
in the app.js script I have the following code:
var wapp = new Wapp();
and I want to do this:
wapp.page('home').onLoad(function() {
// doSomething();
}
// When I call the method 'changePage'
wapp.navigate.changePage('home');
// at the end of the page load 'home' I want to call the function 'doSomething()' inside the 'onLoad' method
how should I define the methods within the class to make sure that at the end of a certain action (in this case at the end of the ajax call) to run the code defined within the 'onLoad' method in app.js?
You are able to assign a function as variable to your class when constructing it. You'll be able to call assigned function later in your code (e.g. in end of the other function)
https://jsfiddle.net/L8c2s6xr/
function func (functionToCall) {
this.functionToCall = functionToCall;
this.doSomething = function () {
this.functionToCall();
}
}
var f = new func (
function() {
alert('this works');
}
);
f.doSomething();
Inside handler.js and I have exported 2 functions. One for initialize() and other handle(). Initialize function use to load handler dynamic based on the application settings. And I have shared variable var handler outside the module.exports function.
handler = new Handler(app); new instance created assign to shared variable var handler. And then inside handle() function shared variable var handler. used
Dynamically require() a file in web request time is not good idea. So initialize() method created and called in application start time.
Let me know suggestion to remove the shared variable 'handler'
var handler;
module.exports = {
initialize : function (app){
var Handler = require(path.resolve(app.basedir, app.settings.handler));
handler = new Handler(app);
},
handle : function handle(ctx) {
var urlToHandle = ctx.url;
return handler.resolveURL(ctx)
.then(function (json) {
ctx.layoutJSON = json;
return ctx;
})
.catch(function (e) {
throw e;
});
}
};
Not sure if I got your right, but if you call the initialize just once you can do something like that:
var app = require('path-to-a-file-which-return-app');
var Handler = require(path.resolve(app.basedir, app.settings.handler));
var handler = new Handler(app);
module.exports = {
handle : function handle(ctx) {
var urlToHandle = ctx.url;
return handler.resolveURL(ctx)
.then(function (json) {
ctx.layoutJSON = json;
return ctx;
})
.catch(function (e) {
throw e;
});
}
};
Now the require will just be called once, since Node will cache it for you.
I'm getting the following js error (on the line of code marked ###) when starting my app:
JavaScript runtime error: Object doesn't support property or method 'messages'
I've previously had this working without knockout, but am trying to add in knockout as I feel this will be easier to maintain in the long run. I suspect that as this is my first venture into both SignalR and Knockout, I've done something blindingly stupid, so any pointers please let me know. The mappedMessages data is fully populated, it's just when it tries to set self.messages it has the issue. Knockout 3.0.0, SignalR 1.1.3.
The full javascript code is below:
$(function () {
var messageHub = $.connection.messageHubMini;
function init() { }
function Message(data) {
this.Operator = ko.observable(data.Operator);
this.text = ko.observable(data.Text);
}
function MessagesViewModel() {
// Data
var self = this;
self.messages = ko.observableArray([]); //### message on this line
}
// Add a client-side hub method that the server will call
messageHub.client.updateMessages = function (data) {
var mappedMessages = $.map(data, function (item) { return new Message(item) });
self.messages(mappedMessages);
}
// Start the connection
$.connection.hub.start().done(init);
ko.applyBindings(new MessagesViewModel());
});
Thanks :)
You should use the viewModel object in the SignalR client methods. Currently, you're trying to use a variable called self, but that variable isn't available in that SignalR client method scope. I have updated your code into a version which I believe should solve your problem, doing as few changes as possible.
$(function () {
var messageHub = $.connection.messageHubMini;
function init() { }
function Message(data) {
this.Operator = ko.observable(data.Operator);
this.text = ko.observable(data.Text);
}
function MessagesViewModel() {
// Data
var self = this;
self.messages = ko.observableArray([]); //### message on this line
}
var viewModel = new MessagesViewModel();
// Add a client-side hub method that the server will call
messageHub.client.updateMessages = function (data) {
var mappedMessages = $.map(data, function (item) { return new Message(item) });
viewModel.messages(mappedMessages);
}
// Start the connection
$.connection.hub.start().done(init);
ko.applyBindings(viewModel);
});
I'm following a guide for XMLHttpRequest2 on the html5 rocks website here. I am also learning how to create classes in JavaScript. Everything seems to be right, but when I test this code on jsfiddle it returns "error" twice from the if statement, and then response returns undefined. I suspect this is an issue with the class?
function Ajax(parameters) {
this.type = parameters.type;
this.url = parameters.url;
this.format = parameters.format;
this.send = parameters.send;
this.xhr = new XMLHttpRequest();
}
Ajax.prototype.initialize = function () {
this.xhr.open(this.type, this.url, true);
this.xhr.responseType = this.format;
this.xhr.onload = this.process();
this.xhr.send(this.send);
};
Ajax.prototype.process = function () {
var self = this;
if (self.xhr.readyState === 4 && self.xhr.status === 200) {
console.log(JSON.parse(self.xhr.response));
} else {
console.log("error");
}
};
var test = new Ajax({type:"GET", url:"http://ip.jsontest.com/", format:"text", send:""});
test.initialize();
console.log(test.process());
I modified your code here: http://jsfiddle.net/FpskW/
You have two problems in your code:
In initialize, this.xhr.onload gains the value of the execution of the proccess function, not the function itself. this.xhr.onload needs a function, and with () in the end of proccess you are executing the code, instead of delegating.
If you do this.xhr.onload = this.proccess, you're passing the proccess function without a specific context. This way, when the XHR object executes the function, the function will have the context of the XHR object. The value of this when the proccess function gets executed, will be the XHR object, not your object. So, when the xhr object tries to execute if (self.xhr.readyState === 4.. it will find that the XHR object doesn't have a property called xhr.
You can do something like this:
Ajax.prototype.initialize = function () {
this.xhr.open(this.type, this.url, true);
this.xhr.responseType = this.format;
// we capture the context of the Ajax object
var self = this;
// and we create a lambda that executes the 'proccess' function always with the context
// of the Ajax object.
this.xhr.onload = function() {
self.process();
}
this.xhr.send(this.send);
};
And that's all.
NOTE: In Javascript, we don't have classes, they're prototypes. :)