How do I reference "this" while method cascading in Dart? - dart

I'd like to reference "this" (a method owner) while method cascading in Dart.
// NG code, but what I want.
paragraph.append( getButton()
..text = "Button A"
..onClick.listen((e) {
print (this.text + " has been has clicked"); // <= Error. Fail to reference "button.text".
}));
I know I can write a code like this by splitting it onto multiple lines.
// OK code, I think this is verbose.
var button;
button = getButton()
..text = "Button A"
..onClick.listen((e) {
print (button.text + " has been clicked");
}));
paragraph.append( button);
Being unable to reference a cascading source object is preventing me from writing shorter code on many occasions. Is there better way to do method cascading?

You can not use this as you would like.
You can simplify your second code snippet with :
var button = getButton();
paragraph.append(button
..text = "Button A"
..onClick.listen((e) {
print (button.text + " has been has clicked");
}));

Related

Custom Components in Crafty.js

I am new to Crafty.js. I am currently working a 2D Top Down RPG using this frame work. I am trying to create a custom component that will contain the Unit's information such as Health, Mana, Name etc. My component's code are as follows:
Crafty.c("UnitInfo", {
init: function() {
this.bind("EnterFrame", function(){
console.log("Custom Component Test: " + this.message);
});
},
unitinfo: function(message) {
this.message = message;
}
});
Then I added this component to a unit which is in my case, an Enemy entity:
enemy1 = Crafty.e('Enemy, 2D, Canvas, Color, enemy_default, SpriteAnimation, Solid, Collision, UnitInfo')
.attr({x: (screenWidth/2) + 150, y: (screenHeight/2) + 150, w: spriteBaseW, h: spriteBaseH, curHealth: 100 })
.checkHits("Skill")
.unitinfo("Random Msg")
.bind("HitOn", function() {
var rndDmg = 0;
if(currentSkill==1) rndDmg = skillDamage.skill1;
else if(currentSkill==2) rndDmg = skillDamage.skill2;
else if(currentSkill==3) rndDmg = skillDamage.skill3;
else if(currentSkill==4) rndDmg = skillDamage.skill4;
rndDmg = randomRange(rndDmg-9,rndDmg);
this.curHealth -= rndDmg;
Crafty.e("2D, DOM, Text, Tween")
.attr({x: this.x, y: this.y})
.textColor("white")
.text(rndDmg)
.textFont({size: "20px"})
.tween({y: this.y-30, alpha: 0.0}, 2000)
.bind("TweenEnd", function(){
this.destroy();
});
if(this.curHealth<=0) {
//this.destroy();
//console.log("An Enemy was killed!!!!");
}else{
console.log("Enemy HP: " + this.curHealth + ", Damage Taken: " + rndDmg);
}
})
.bind("EnterFrame", function() {
enemyAI(this);
});
When I execute the code, it shows me this error:
console error
I believe that the unitinfo() is properly working as the "Random Msg" is appearing on the console logs and it is being executed every frame. I just don't understand why "this" is being recognized as undefined. Can someone help me on this?
This is because you're attempting to call bind on the result of unitinfo(), but that method doesn't return the entity.
This is a fundamental aspect of javascript, but it's definitely a gotcha when implementing custom components in Crafty. From the docs
Keep in mind that the method chaining technique (calling e.place().color()) is only possible because we explicitly return this from our custom method. Forgetting to do so can be a common source of errors, so keep that in mind if you get a hard-to-pin-down "method undefined" message.
i.e. when you define a method, you have to explicitly return this to use it in this manner.

"CS0162: Warning as Error: Unreachable code detected" on Razor View

I have the following code within a script tag on my razor view:
self.regions = [];
#foreach(var region in Model.OperationRegions)
{
<text>
self.regions.push({
regionid: '#region.Region_Id',
regionname: '#region.Title',
selected: ko.observable(#(Model.RegionsList.Contains(region.Region_Id).ToString().ToLower()))
});
</text>
}
self.categories = [];
#foreach(var category in Model.Categories)
{
<text>
self.categories.push({
categoryid: '#category.Category_Id',
title: '#category.Title'
});
</text>
}
For clarity, the code outside of the foreach loops and within the text tags are Javascript and the purpose of the razor code is to populate my Javascript arrays with data from the server.
When I run this I am currently getting a server error saying "CS0162: Warning as Error: Unreachable code detected"
The error is thrown on the second "foreach" in the snippet.
Surprisingly I couldn't find another question referring to this error message on an MVC razor page so I'm posting this here.
My question is why is that line of code considered to be unreachable? I will update this question if I find anything else on my page to be relevant to the issue as I try to debug.
The error has disappeared now. I had renamed a property of my model and not recompiled before trying to load the page again. Recompiling made the error go away. I have no idea how the root cause translated to the error message shown but its fixed now in any case.
This is an extremely poor way to handle this. There's no need to build an array piece by piece like this. Just convert your list to JSON.
self.regions = #Html.Raw(Json.Encode(Model.OperationRegions.Select(region => new {
regionid = region.Region_Id,
regionname = region.Title,
selected = Model.RegionsList.Contains(region.Region_Id)
})));
The only thing this can't handle is making selected an observable. However, you can simply loop through the array and fix this:
for (var i = 0; i < self.regions.length; i++) {
self.regions[i].selected = ko.observable(self.regions[i].selected);
}
However, the better approach is to use another view model:
var OperationRegionViewModel = function (data) {
var self = {};
self.regionid = ko.observable(data.regionid);
self.regionname = ko.observable(data.regionname);
self.selected = ko.observable(data.selected);
return self;
};
Then, you can just do something like:
var regions = #Html.Raw(Json.Encode(Model.OperationRegions.Select(region => new {
regionid = region.Region_Id,
regionname = region.Title,
selected = Model.RegionsList.Contains(region.Region_Id)
})));
self.regions = $.map(regions, new OperationRegionViewModel);
Or, even better build your JSON all at once:
var json = #Html.Raw(Json.Encode(new {
regions = Model.OperationRegions.Select(r => new { ... }),
categories = Model.Categories.Select(c => new { ... }),
// etc
});
Then, inject this all into your view model:
var viewModel = (function (json) {
// other stuff
self.regions = $.map(json.regions, new OperationRegionViewModel);
self.categories = $.map(json.categories, new CategoryViewModel);
// etc
})(json);

Invalid Property on Extended FIORI Application

We are implementing an extended My Quotations Fiori application. Basically we added a new field Sales Order to the UI. The field fetches data from the backend so we also extended our OData service. On the first view, we can successfully call the data. But whenever we navigate to the next view via clicking Edit button, we get this error
Property 'SalesOrder' is invalid. Choose "Refresh" to update pricing information.
Anyone has an idea on how to solve this?
Here is our custom code for S3 view controller. We used WEB IDE to create the extension btw. The second function is for the creation of the Sales Order whenever the quotation has no associated SO tied to it.
manageSalesOrderFields: function() {
alert("manageSalesOrderFields");
var salesOrderId = "";
// hide all fields
view.byId("salesOrderLabel").setVisible(false);
view.byId("salesOrderText").setVisible(false);
view.byId("triggerSalesOrderLabel").setVisible(false);
view.byId("triggerSalesOrderButton").setVisible(false);
$.getJSON("/sap/opu/odata/sap/zlord_my_quotation_srv/QuotationHeaderSet('" + quotationId + "')",
function(data) {
alert("enterHere");
salesOrderId = data.d.SalesOrder;
alert(salesOrderId);
if (salesOrderId !== "" ){
view.byId("salesOrderLabel").setVisible(true);
view.byId("salesOrderText").setVisible(true);
}else{
view.byId("triggerSalesOrderLabel").setVisible(true);
view.byId("triggerSalesOrderButton").setVisible(true);
view.byId("triggerSalesOrderButton").detachPress(sap.ui.controller("...").createSalesOrder);
view.byId("triggerSalesOrderButton").attachPress(sap.ui.controller("...").createSalesOrder);
}
});
},
createSalesOrder: function () {
var createSalesOrderDialog = new sap.m.Dialog("createSoDialog", {
title: "Create Sales Order",
icon: "sap-icon://sales-order",
content: [
new sap.ui.core.HTML({content:"<p style='margin:0;padding: 16px;'>Do want to create a sales order?</p>"})
],
buttons:[
new sap.m.Button({
text: "Yes",
press : function() {
var oModel = new sap.ui.model.odata.ODataModel('/sap/opu/odata/sap/zlord_my_quotation_srv/');
var oParameter = {
"QuotationID" : quotationId
};
oModel.callFunction('/CreateSalesOrder', 'GET', oParameter, 'null',
function (oData, oResponse) {
var responseMessage = JSON.stringify(oResponse.body);
var responseMessageStart = responseMessage.search('<d:Message>');
var responseMessageEnd = responseMessage.search('</d:Message>');
responseMessage = responseMessage.substring(responseMessageStart + 11, responseMessageEnd);
//show MessageToast
sap.m.MessageToast.show(responseMessage);
view.byId("triggerSalesOrderLabel").setVisible(false);
view.byId("triggerSalesOrderButton").setVisible(false);
console.log(responseMessage);
},
function (oError) {
sap.m.MessageToast.show('Error - see log');
console.log(oError);
}
);
createSalesOrderDialog.close();
createSalesOrderDialog.destroy();
}
}),
new sap.m.Button({
text: "No",
press : function() {
createSalesOrderDialog.close();
createSalesOrderDialog.destroy();
}
})
]
});
createSalesOrderDialog.open();
}
We didn't edit anything on the next view controller (CreateQuotations.view.controller.js) since it is not relevant for us to show the SO number on that view.
The error is because of this line:
salesOrderId = data.d.SalesOrder;
How to fix?
Step 1 : Check results first in network tab for the call:
/sap/opu/odata/sap/zlord_my_quotation_srv/QuotationHeaderSet('quotationIdId');
Sample:
Step 2: Check the results hierarchy . How?
console.log(data); //in success call
Step 3: Then restructure your statement to something like this
salesOrderId = data.d.results[0].SalesOrder;
Hope this helps!

initialize a listview outside of a page

I am building a single page application using jQuery Mobile.
In the header I have a "menu" button that opens a popup with a listview.
I would like to define this popup dialog and reuse it for all pages.
Reusing a popup outside a page works fine, but listview inside the popup does not get enhanced (because listview internally uses parent page to resolve links included in the list).
Question: is it possible to use a listview widget outside of a page? (I do understand that I might have to specify a base url for this to work, but I don't think that will be a problem).
No, its not possible. When you create a dynamic popup, which doesnt reside in a single page, IT WILL WORK, because popups were never meant to be used/page. But, listview on the other hand, requires the list to lie in a parent page. The refresh method of listview expects it to be in parent. Look at this function which is called when a listview refresh happens :
_createSubPages: function () {
var parentList = this.element,
parentPage = parentList.closest(".ui-page"), //<-- This line
parentUrl = parentPage.jqmData("url"),
parentId = parentUrl || parentPage[0][$.expando],
parentListId = parentList.attr("id"),
o = this.options,
dns = "data-" + $.mobile.ns,
self = this,
persistentFooterID = parentPage.find(":jqmData(role='footer')").jqmData("id"),
hasSubPages;
// blah blee blah
}).listview();
See the second line in the function. It expects a page to be there. Tough luck bro :)
PS : This is the closest i could get : http://jsfiddle.net/hungerpain/8qq62/1/
EDIT
Here's a hacky way. You could dynamically create a hidden <span/> in your data-role=page div and add the <ul/> in it. Then you could refresh it, after which you could move it to the dynamic popup. Then you'll have to remove that hidden span element. Here's the code :
$.extend({
"makePopup": function (array) { //you could add more if you want here, such as callbacks to the click function of the button,etc.
var $popup;
//creat popup element
$popup = $("<div/>", {
"data-role": "popup",
"data-theme": "a",
"data-overlay-theme": "a",
"data-transition": "pop"
}).popup();
//create list
$list = $("<ul/>", {
"data-role": "listview",
"id": "templist"
}).html(function () {
var li = [];
for (var i = 0; i < array.length; i++) {
li.push($("<li/>").html(array[i]));
}
return li;
})
//create close element
var $close = $("<a/>", {
"data-role": "button",
"html": "Close",
"href": "#",
"data-theme": "a"
}).on("click", function () {
//click event of close element
$(this).closest("[data-role=popup]").popup("close");
}).buttonMarkup();
//add a span to page, refresh list, etc
$.mobile.activePage.append("<span id='temp'></span>").find("#temp").hide().append($list).promise().done(function () {
$(this).find("#templist").listview().listview("refresh");
});
//create content div - makes a nice jQM page structure.
var $content = $("<div/>", {
"data-role": "content",
//move li to popup
}).append($("#temp").find("#templist"), $close);
//remove span
$("#temp").remove();
//append $close to $content, then append $content to $popup
$content.appendTo($popup)
return $popup;
}
});
And you could pass an array to this :
$.makePopup(["Sweet Child 'O Mine", "Summer of '69", "Smoke in the Water", "Enter Sandman", "I thought I've seen everything"]).popup("open");
Here's an updated demo : http://jsfiddle.net/hungerpain/8qq62/7/
But obviously this is hacky.

jQuery-UI Dialog Buttons - pass argument to btn click function

I'm a begginer jQuery dev, and I'm using the jQuery UI dialog to show up properties of an object (whatever).
var $dialog = $('<div></div>')
.html('This dialog will show every time!')
.dialog({
autoOpen: false,
title: 'Properties'
});
So this is the dialog, and let's say I have a FOR structure in which I add properties (p tags) and for some of those properties I want a button.
var dialogHtml = "";
var dialog_buttons = {};
for (var key in d.properties){
var str;
var str = '<p>' + something + '</p>';
if (condition){
dialog_buttons[key] = function()
{ functionName(key); };
}
dialogHtml = dialogHtml + str;
}
$dialog.dialog( "option", "buttons", dialog_buttons );
$dialog.dialog('open');
And somewhere else I have the function:
function functionName(key){
// something something
}
This is where I have the problem: the key variable that's passed to the function... when the button is called the key is the last value from the iteration.
Let's say we have keys 1, 2, 3, 4 then when the button is clicked, the key parameter will be 4.
I want when I click a button from the dialog, to know which button was pressed.
Can anybody help me?
Thanks!
Using the event data from the click event (see here)
$('#btn').click(function(e) {
functionName(e.target);
});
Explanation of Event.Target

Resources