I'm trying to get a CFC (webCFC) with a remote function to return an instance of a different CFC (objCFC).
Here are the CFCs:
#webCFC
component {
remote function displayCFC(version=1) {
if(version==1) {
return new baseCFC();
} else {
return new objCFC();
}
}
}
#baseCFC
component
accessors="true"
persistent="true"
{
property name="name" default="pete";
}
#objCFC
component
extends="baseCFC"
persistent="true"
accessors="true"
{
property name="age" default="30";
}
If I call this URL: /webCFC.cfc?method=displayCFC&returnFormat=json, I get this response:
{
"name" : "pete"
}
which is fine. If I call this URL: /webCFC.cfc?method=displayCFC&returnFormat=json&version=2, then the response is missing the property from baseCFC
{
"age" : 30
}
I would expect the response to look like this:
{
"name" : "pete",
"age" : 30
}
I know that I can use the setName() and getName() functions on objCFC, it is definatly extending baseCFC but the extended properties don't show if I access the CFC through the browser.
Is it possible to get this to work?
This could be related to the seralizejson bug (not sure when will it ever be bug free).
A workaround would be to implement your own getMemento() or toJSON() method that returns all the desired properties in a struct. Then serializeJSON that struct instead.
Related
I would like to write web method(WebApi 2) as
GetArchiveDataForEngagements(collection of EngagementNumbers)
I have written code as
public async Task<IHttpActionResult> GetArchiveDataForEngagements(string[]
engagementNumber)
{
return Ok();
}
and using postman ,My input is like below
{
"engagementNumber":["one","two"]
}
I am getting "null" value for engagementNumber in web method.
Can anyone suggest , how can I achieve this?
You cannot pass data to a GET method using values in a body.
You could pass values as multiple query string values like this:
https://example.com/controller/GetArchiveDataForEngagements?engagementNumber=one&engagementNumber=two
You have not given enough routing information to make an accurate guess at the URL, but the query string part is the important part.
public class TEST
{
public string[] engagementNumber { get; set; }
}
[HttpPost]
[Route("test")]
public async Task<IHttpActionResult> GetArchiveDataForEngagements(TEST t)
{
return Ok();
}
Postman URL:
http:/localhost:8888/api/testCon/test
Postman Body: JSON(application/json)
{
"engagementNumber":["one","two"]
}
TestCon is the name of the controller.
I'm using the native Bluetooth serial library and trying to mock data for testing in the browser. By experimentation (and a little reading) it seems that the way to do this is to check for the 'cordova' platform:
export class BluetoothServiceWrapper implements OnDestroy, OnChanges {
...
private isEmulated:boolean = true;
...
constructor(platform:Platform) {
platform.ready().then(() => {
this.isEmulated = !platform.is('cordova');
});
}
The strange thing is that this works in some parts:
connect(device:BluetoothDevice) {
return Observable.create(observer => {
...
if (!this.isEmulated) {
...
}else{
... // this is executed in the browser
}
}
}
But in other parts the this.isEmulated is undefined:
write(data:any):Promise<any> {
if (!this.isEmulated) {
return BluetoothSerial.write(data);
} else {
.... // this never gets executed
}
}
Am I overcomplicating this and there is an easier way to check if we are using browser/emulation? Or is there some error in the way the context is being passed over?
I should mention that both methods get the same members when accessing 'this' i.e. the BluetoothServiceWrapper members. In the case of the 'write' function though the isEmulated variable is hidden/undefined.
Ok, this was a bit of a trap. The important piece of information that was missing from the original post was that I had another component/service perform the following:
if (!this.isConnected && (!this.isConnecting)) {
this.bluetoothServiceWrapper.connect(device).subscribe(data => this.tuningModuleService.onData(data), console.error);
this.tuningModuleService.setOutputFunction(this.bluetoothServiceWrapper.write);
}
Inside the service above I would be calling this.write('somedata'), using the function above given as reference.
The service:
outputToSerialFn: any;
constructor(applicationRef: ApplicationRef, platform: Platform) {
...
// default (mock) output function
this.outputToSerialFn = function (data) {
return new Promise((resolve, reject) => {
console.log('Mock BT OUT', data);
})
};
}
setOutputFunction(outputToSerialFn: any) {
this.outputToSerialFn = outputToSerialFn;
}
The problem is that during calls the write function would get the scope of the Service using it instead of the BluetoothWrapper service.
One solution is to replace the call above with:
this.tuningModuleService.setOutputFunction(this.bluetoothServiceWrapper.write.bind(this.bluetoothServiceWrapper));
The key word is bind.
This is probably not the best pattern but might help someone who is also struggling with this. The lesson here is that passing functions as parameters overrides the original function scope.
The following returns all active items.
activeItems: Ember.computed('items.#each.status', {
get() {
return this.get('items').filter((item) => {
return item.get('status') === 'active';
});
}
})
// Template
{{#each activeItems as |activeItems|}}
{{activeItem.status}}
{{/each}}
All of above works. Now lets say I want to create a computed property that picks out the last activeItem. I tried:
activeItem: Ember.computed('activeItems', {
get() {
return this.get('activeItems').lastObject;
}
}),
// Template
{{activeItem.status}} <-- returns nothing
Why is this and how can I get it to work?
I see 2 problems:
Your computed property has the incorrect dependent key. By only relying on activeItems, the problem will only update when the activeItems property returns a new object, not when the contents are updated. You should be watching activeItems.lastObject.
lastObject is a computed property, which means you might not be able to access it without using Ember's get() function.
Try this:
activeItem: Ember.computed('activeItems.lastObject', {
get() {
return this.get('activeItems.lastObject');
}
})
Or, for the shorthand:
activeItem: Ember.computed.reads('activeItems.lastObject')
I have a question about routing while testing packages. The function setRoutes creates new routes in the test file as follows:
class PackageTests extends \Orchestra\Testbench\TestCase {
protected function setRoutes()
{
Route::group([
'prefix' => Package::functionToCall1(),
'before' => 'filter'
], function() {
Route::get('/', function () {
return "hello";
});
});
Route::enableFilters();
}
protected function getEnvironmentSetUp($app)
{
$this->app = $app;
$this->setRoutes();
Config::set('app.url', "http://localhost/" );
}
public function testFunction1()
{
$crawler = $this->call(
'GET',
'http://localhost/'
);
// doing this call, the function on the prefix is called
$this->assertResponseOk();
}
}
Inside the function called in the prefix, functionToCall1() urls are not taken successfully. A call to URL::current() returns "/" and a call to Request::fullUrl() returns "http://:" when phpunit is executed but they returns the full url when used executing a url in the browser. This is the code of the package:
class Package
{
function functionToCall1()
{
var_dump(URL::current() ); // returns "/"
var_dump(Request::fullUrl()); // returns "http://:"
// I want them to return 'http://localhost'
}
}
I tried setting up the url Config::set('app.url', "http://localhost/" ); but it was useless.
To sum up, is there a way to call a function in the prefix and get the testing url?
Thanks, I would really appreciate your answers :)
I have had to deal with a similar issue. My solution was found here:
Mocking Laravel's Request::segment method
Apparently there is an order of operations issue with testing a Request facade.
I was trying to use Request::segments() before the request was being built, so there were never any segments to return.
I imagine it's the same problem with Request::fullUrl().
Here is my solution:
class MyTestClass extends TestCase
{
public function setUp()
{
// No call to parent::setUp()
$this->app = $this->createApplication();
$this->app->request->server->set('REQUEST_URI', '/some/uri');
$this->client = $this->createClient();
$this->app->boot();
}
public function testWhatever()
{
$this->call('GET', '/some/uri');
}
}
This allows me to get the request data properly, even though it looks pretty bad.
I have a handful of computed properties defined on a component. I'd like to refactor these computed properties to live within a messages object on the component. When I make a call to get one of the computed properties elsewhere, I'm returned an instance of Ember's ComputedProperty object, rather then the translation string I expected. Looking at the documentation, Ember.get should invoke the computed property and return the object itself, the property value or null.
What am I missing? How would I go about structuring these nested computed properties so that I can access them using the get/set interface elsewhere in the component?
App.ValidatedDateComponent = Ember.Component.extend({
format: null,
label: null,
messages: {
invalidDateMsg: (function() {
return I18n.t('%{date} must be a valid date. %{format}', {
date: this.get('label'),
format: this.get('format')
});
}).property('label', 'format')
},
validate: function(value, status) {
if (!moment(value).isValid()) {
return status(false, Ember.get(this.messages, 'invalidDateMsg'));
} else {
return this._super(value, status);
}
}
});
Ember only supports defining computed properties while extending Ember.Object class, the exception to the rule is while defining a Ember.Mixin.
Defining the top level of the nest
var nest = Ember.Object.extend({
foo: function() {
return "something";
}.property()
});
Creating an instance of it
App.IndexController = Em.ArrayController.extend({
messages: nest.create()
});
Template
{{messages.foo}}
http://emberjs.jsbin.com/UhUvOvU/1/edit
So in your case you could, if you really wanted to, do:
messages: Em.Object.extend({
invalidDateMsg: function() {
return I18n.t('%{date} must be a valid date. %{format}', {
date: this.get('label'),
format: this.get('format')
});
}.property('label', 'format')
}).create(),