Javascript parameter dynamically change using Play - javascript

I have a javascript request like this to pass data to play framework and based on the different propertyKey, the event should have different parameter.
I do something like this.
The js is used by multiple windows. So this._propertyKey will change based on different windows.
_postEvent: function(customData) {
var propertyKey = this._propertyKey;
var Event = {
propertyKey : customData
},
url = play.url({
alias: 'controllers.eventController.trackEvent',
args: Event,
withCsrf: true
});
return $.ajax(url, {
type: 'POST'
});
},
The problem when I trigger this code. According to the request it sends, it is always Event.propertyKey instead of the customized propertyKey I pass in. For example, if for this window, propertyKey = 'region'. I want 'region' to pass in as the parameter. But no matter what propertyKey is, the post request always sends Event.propertyKey = XXX instead of Event.region = XXX.
Is there a way to pass in the propertyKey here Is use to make it change dynamically based on different pages?

When a function is called as a method of an object, its this is set to the object the method is called on. MDN Reference
To fix that part of the code, use window instead of this.
In order to set a property name to be the value of another variable, you have to create the object first, and then set the key/value pair using []. SO Reference
var Event = {};
Event[propertyKey] = customData;
var url = play.url({
alias: 'controllers.eventController.trackEvent',
args: Event,
withCsrf: true
});

Related

SAP OpenUI5 - Call function inside attachRequestCompleted

I have a question about attachRequestCompleted in SAP Open UI5.
My code Looks like this:
test : function (oEvent) {
model = new sap.ui.model.json.JSONModel();
// Load JSON in model
model.loadData("http://localhost:8080/getJSON");
model.attachRequestCompleted( function(){
console.log(model.getData());
this.makeSomething()
});
},
I want to call my function makeSomething after the model is loaded but it's not possible.
I tried to call it after the function like this. The function gets called but the model isn't loaded.
test : function (oEvent) {
model = new sap.ui.model.json.JSONModel();
// Load JSON in model
model.loadData("http://localhost:8080/getJSON");
model.attachRequestCompleted( function(){
console.log(model.getData());
}, this.checkElement());
},
Is this even possible?
The this keyword in JavaScript is tricky. As W3schools states here:
In JavaScript, the thing called this, is the object that "owns" the JavaScript code.
The value of this, when used in a function, is the object that "owns" the function.
The value of this, when used in an object, is the object itself.
The this keyword in an object constructor does not have a value. It is only a substitute for the new object.
The value of this will become the new object when the constructor is used to create an object.
In your case, if you call this inside your test method, this will refer to the current controller. You can use this inside your method to access other methods of the controller.
However, if you use this inside your callback method, this - the owner of the code - is no longer the controller. It is your callback method. this.makeSomething() does not exist.
The common way around this is to create a variable usually called that, to which you give the value of this while this has the value you want to access later on. You can then access it from your callback method; in the callback method, the that variable will not have changed, whereas this will be different.
A code sample is worth a thousand words. See my changes below.
test : function (oEvent) {
var that = this;
model = new sap.ui.model.json.JSONModel();
// Load JSON in model
model.loadData("http://localhost:8080/getJSON");
model.attachRequestCompleted( function(){
console.log(model.getData());
that.makeSomething();
});
},
When using UI5, I usually create a variable at the same level as my controller methods called _globalThis. In the onInit method, I then assign it the value of this and can then access that same variable from every one of my callback methods.

Event handling in Titanium with data argument

Ok, I just stepped into something tricky. I need to fire an event on my app everytime a major update happens (because I want multiple windows opened, therefore they need to be updated). The thing is, with that event, I wish to pass an argument, something like this:
Ti.App.fireEvent('updateViews', {data: my_data});
So far so good, but when I receive this event I want to be able to access its data. The only way I found out to do so is to create an anonymous function, like this:
Ti.App.addEventListener('updateViews', function(data)
{
var name = data.name;
});
Great! That works! Now the big problem.. when I close this window, I need to remove that listener... Otherwise I'll end up with a memory leak. The thing is, if I change the anonymous function and pass it to a handler, I'm unable to access the data - but if I don't, I cant reference the function to successfully remove it. Please, help!
PS: There IS a way to do this, of course I could pass the data using Alloy.Globals (or the equivalent in the standard Ti), but I want a CLEAN, elegant solution that does not involve using Alloy.Globals. Thanks in advance.
Is there a reason you need to use global app events? They make code more difficult to maintain and result in tighter coupled dependencies that are brittle when something changes. It also increases side effects when attempting to understand the code (Your future self will forget and you will get lost and confused).
The problem your experiencing is probably from the assumption that by assigning to a data property that it becomes the argument. The object you pass into fireEvent will be the object passed to the callback argument.
Ti.App.fireEvent('updateView', {data: {name: "foo"}});
Ti.App.addEventListener('updateView', function(e) {
var name = e.data.name;
});
That being said, events in general can easily pass data via the fireEvent as you demonstrated. I find in cases of 'click' events I'm more interested in static data then in dynamic data. I use partial applications for this: (example uses underscore provided by Alloy, but the functionality can easily be polyfilled)
var _ = Alloy._;
var titles = ['foo', 'bar', 'baz'];
var messages = [
'This ia s foo message.',
'But a bar message is better.',
'Then again a baz message trumps them all.'
];
function onClick(message, e) {
e.cancelBubble = true; // Not required but shows how to access the event object
alert(message);
}
var tableData = _(titles).map(function(title, index) {
var row = Ti.UI.createTableViewRow({title: title});
row.addEventListener('click', _.partial(onClick, messages[index]));
return row;
});
var table = Ti.UI.createTableView({
data: tableData
});
So.. I figured it out. You can actually do that.. The problem was that I was registering the handler the wrong way. It will work if you just only set the handler to receive data. Example for the above code:
var handler = function(data) {
var name = data.name;
alert(name);
}
Ti.App.addEventListener('updateViews', handler);
Then, to remove it:
Ti.App.removeEventListener('updateViews', handler);

Ajax setting 'context' does not affect 'data's location

the following Ajax works
function Retrieve(el) {
var table = this;
this.el = el;
this.fetchInfo = function () {
$.ajax('data.html', {
context: table,
<!-- QUESTION HERE -->
data: {
location: table.data('location')
},
success: function (response) {
this.el.find('.info').html(response).fadeIn();
},
}
}
but I am wondering why I cannot replace table.data with this.data on the denoted line. Since I set the context to table variable, this now should be set to whatever table is referring to right? This holds true in the context of other members of the Ajax object (including success), but not for the members of data. Why is this the case?
data('name') extracts value from a tag with attribute data-name
The context variable you've given only applies within the success callback, and doesn't change anything for any of the other parameters passed to $.ajax.
The answer therefore depends on how you actually call fetchInfo. The data: variables will be resolved in whatever context fetchInfo has. Given you're experiencing problems, this suggests that you are not calling the function with your Retrieve object as its context.
EDIT this line is your problem:
this.el.on('click', 'button', this.fetchInfo);
just because you've referred to this.fetchInfo, doesn't make this the context when it's subsequently invoked. Try this instead:
this.el.on('click', 'button', $.proxy(this.fetchInfo, this));
Looking at the documentation of $.ajax(), I found that the context gets set to callbackContext variable. This gets with use success, error, beforeSend, complete, but not with data option.
AJAX options gets assigned to a variable named s:
s = jQuery.ajaxSetup({}, options),
The data option gets converted to string, but callBackContext is not used.
// Convert data if not already a string
if (s.data && s.processData && typeof s.data !== "string") {
s.data = jQuery.param(s.data, s.traditional);
}
So it is necessary to set specify the element for data using a variable other than this.

How to pass namespace variable into click function param variable? jQuery

So I found an awesome solution to get around needing to use Global variables in jQuery here. Everywhere I say namespace, originally I was going to use a Global var.
However I'm not able to send my namespace variable through a param on a simple click function.
I want to do this because I have these variables that need to be saved and used to create modal windows as well as to let the app know what dynamically created buttons control what modal.
So below is an example of my namespace object where I first create the variables
My jQuery namespace object:
$.reg = {
masterRole : " ",
role_ID : " ",
row_Name : " ",
ary_Check_Role : []
};
$(document).ready(function () {
...
As you go through the app the values for those namespace variables get set when you click this button (grabs data from HTML)
Variables are set on my roleBtnClicked function
function roleBtnClicked(event){
$.reg.masterRole = $(this).html(); /* Get role name: Actor */
$.reg.role_ID = $(this).attr('role'); /* Get role-1 */
$.reg.rowName = $(this).attr('row'); /* Get row-role-1 */
$.reg.blueBtn = $(this).attr('blue'); /* Get blue-btn-1 */
Now a modal window pops up, after clicking some checkboxes and pushing data into an array, when you click the done button(below) all the variables need to be saved into the namespace vars again.
My done button click Function, where I'm trying to pass my namespace variables via param vars
$(".doneButton").click(
{
param1: $.reg.masterRole,
param2: $.reg.role_ID,
param3: $.reg.rowName,
param4: $.reg.ary_Check_Role
},
doneBtnClicked);
function doneBtnClicked(event){
alert('$.reg.roleName = '+$.reg.roleName);
alert('event.data.param1 = '+event.data.param1);
masterRole= event.data.param1;
role_ID = event.data.param2;
rowName = event.data.param3;
ary_Check_Role = event.data.param4;
Note the 2 Alerts above in the click function, the first one will display the correct value, however the 2nd one doesn't display anything. Also Having a problem getting the Array to come through as well.
So questions: Should I be doing it this way? How do you pass an Array into a jQuery namespace correctly and then get it passed into a click function param?
First off, you should avoid putting things into the jQuery object. Use closures for that.
Second: You should use HTML data-... attributes and jQuery data() to attach custom properties to HTML elements. Avoid using non-standard properties.
Third: You can use separate named function definitions for event handlers, but it makes most sense when you actually re-use those functions for different elements across your code (you don't seem to do that). Using anonymous functions that you pass directly to .click(), for example, results in more understandable code.
// use this shorthand instead of $(document).ready(function () { ... });
$(function () {
// variable reg will be available to all functions
// defined within this outer function. This is called a closure.
var reg = {
masterRole : " ",
role_ID : " ",
row_Name : " ",
ary_Check_Role : []
};
$(".roleButton").click(function (event) {
// modify state
reg.masterRole = $(this).html(); /* Get role name: Actor */
reg.role_ID = $(this).data('role'); /* Get role-1 */
reg.rowName = $(this).data('row'); /* Get row-role-1 */
reg.blueBtn = $(this).data('blue'); /* Get blue-btn-1 */
// note that this requires markup like this:
// <button data-role="foo" data-row="bar" data-blue="baz">
// ...
});
$(".doneButton").click(function (event) {
// debug output
alert(JSON.stringify(reg, 2, 2));
});
});
Use multiple $(function () { ... }); blocks to separate things that should be separate.
Don't forget to always use var for every variable you declare. Variables declared without var will be global - and you don't want global variables.

JQuery.ajax() makes a copy of the settings object?

JQuery.ajax() accepts a settings argument. The functions for success or error (for example) run in the context of this object.
var arr = [];
var a = {
url : '/',
arbiteraryProperty: 'yeah!',
complete:function () {
console.dir(arr[0]);
}
};
arr.push( a );
$.ajax( a );
runs the command and then prints the attributes of the first element of arr (which is a) as follows:
arbiteraryProperty : "yeah!"
url : "/"
complete : function()
Now the problem is that the this keyword inside the above complete function is not actually referring to the settings object. It is interesting because it seems JQuery is making a copy of the settings object.
var arr = [];
var a = {
url : '/',
arbiteraryProperty: 'yeah!',
complete:function () {
console.log(this.arbiteraryProperty );
//this prints 'yeah!'
this.arbiteraryProperty = 'nope!';
console.log( this.arbiteraryProperty );
//this prints 'nope!' so the value of the attribute in this is changed
console.log( a.arbiteraryProperty );
//this prints 'yeah!' ie. the value originally existed in the settings object
}
};
arr.push( a );
$.ajax( a );
The question is: does JQuery really create a duplicate copy of the setting object? And if yes, how can I force it to use my object?
I have an application where I need to save these objects in a queue and expect them to be updated when they run. I guess one alternative is to use the context settings for the $.ajax(). However this behavior of this function (making a copy of the settings object) wasn't documented. Or I missed it?
Yes, jQuery creates a new options object when you call jQuery.ajax(). The result is a combination of the settings object you passed and the global jQuery.ajaxSettings object, so that you have the correct default values and any settings you've set globally, even when you don't explicitly set them in the object passed.
This can be seen in the source code for jQuery 1.9 on line 7745:
// Create the final options object
s = jQuery.ajaxSetup( {}, options ),
Generally you use the context property to specify a different value for this inside the callback functions, so:
options = {
url: '/',
...,
context: a
}
However, the circular reference in your case (a referring to itself in one of its properties) may cause issues if the merge does a deep copy.

Categories

Resources