Empty value on Polymer computed attribute - javascript

I am trying to use computed attribute in Polymer but I always get an empty value. In this case I have an attribute in my custom element called datagraph. And I make a post request to a server, get a JSON file, calculate the result and then show it. This is my custom element:
<dom-module id="cost-card">
<template>
<style>
p.datos3{
color: #10cebc;
text-align: center;
font-size: 22px;
margin-top: 0px;
}
</style>
<p class="datos3">{{datagraph}}</p>
</template>
<script>
Polymer({
is: "cost-card",
properties:{
usr:{
type: Number,
value: 2
},
command:{
type: String,
value: "SP_GetCostoCampania"
},
datagraph:{
type: Number,
computed: 'getCost(command,usr)'
}
},
getCost: function(command,usr){
var options = {
hostname: 'localhost',
path: '/',
port: 8081,
secure: false,
method: 'POST',
headers: {
'x-powered-by': 'HTTPClient.js'
},
'Content-Type': 'application/json'
}
var innerCost;
var example1 = new HTTPClient(options);
example1.post("/executeGraph1?command="+ command + "&param1=" + usr, function (err, res, body) {
body = JSON.parse(body);
innerCost = body[0].price * body[0].exchengeRate;
});
return innerCost;
}
});
</script>
</dom-module>
I have an express server running, information is being delivered correctly but the {{datagraph}} tag keeps empty. I think it may be because the post request is an anychronous task, and the value is being delivered later but I have also tried using Promise with the same result.
Does anyone know the proper way to do this?

As you've hinted, getCost is always going to return undefined because return innerCost is going to execute before the post's callback.
Computed properties are meant to take in other properties as arguments and are designed to be synchronous. If getCost took in some argument, even then you would want to use an observer that directly sets this.datagraph within the callback.
Since you aren't feeding any arguments into getCost, I would suggest you instead use a ready callback that makes the post request and sets this.datagraph within the callback.
For example:
Polymer( {
is: "cost-card",
properties: {
usr: { type: Number, value: 2 },
command: { type: String, value: "SP_GetCostoCampania" },
datagraph: Number
},
observers: [ "getCosto(command, usr)" ],
getCosto: function ( command, usr ) {
var options = {
hostname: "localhost",
path: "/",
port: 8081,
secure: false,
method: "POST",
headers: { "x-powered-by": "HTTPClient.js" },
"Content-Type": "application/json"
};
const uri = `/executeGraph1?command=${command}&param1=${usr}`;
new HTTPClient( options ).post( uri, ( err, res, body ) => {
// values have changed, ignore result (ideally cancel the HTTP request)
if ( command !== this.command || usr !== this.usr ) return;
body = JSON.parse( body );
this.datagraph = body[ 0 ].price * body[ 0 ].exchengeRate;
} );
}
} );

Related

JS HTTP post YAML

I am unable to post a yaml throught http in js. The code works when I used JSON.stringify(text) for body and have content-type application/json. If I use YAML stringify, body on server side is just {}.
I have areatext where I enter a text (like yaml format) in html e.g.
martin:
name: Martin D'vloper
job: Developer
skill: Elite
Client:
$('#create-yaml2').on('click',async function () {
var text = $('#yaml-create').val();
// console.log(text)
var textYAML = YAML.stringify(text);
var options = {
hostname: 'myhostname',
port: 80,
path: `/api/postyaml`,
method: 'POST',
body: textYAML,
headers: {
'Content-Type': 'text/x-yaml'
}
};
var executeReq = http.request(options);
executeReq.write(textYAML);
executeReq.end();
});
EDIT:
Function in server side, that prints not an empty {} when posting JSON.
exports.functionCalled = async function (req, res) {
console.log('\n\n\n\n')
console.log(req.body)
console.log('\n\n\n\n')
try {
res.send(`RECEIVED`);
} catch (upgradeErr) {
res.status(422).json({
message: `Failed`,
error: upgradeErr
});
}
}
You already have a string coming from HTML, so you don't need to call YAML.stringify once again - text is already a string.
$('#create-yaml2').on('click',async function () {
var text = $('#yaml-create').val();
// console.log(text)
var textYAML = text;
var options = {
hostname: 'myhostname',
port: 80,
path: `/api/postyaml`,
method: 'POST',
body: textYAML,
headers: {
'Content-Type': 'text/x-yaml'
}
};
var executeReq = http.request(options);
executeReq.write(textYAML);
executeReq.end();
});
You may want to do something like
$('#create-yaml2').on('click',async function () {
var text = $('#yaml-create').val();
try {
YAML.parse(text)
} catch(e) {...}
...
send request
to make sure there was a valid YAML provided
YAML.stringify converts a JavaScript data structure to a string containing YML.
You don't have a JavaScript data structure, you just a string containing YML.
Almost. You have an error in it. You can't use a raw ' in a YML string that isn't quoted.
So:
Fix your YML:
martin:
name: "Martin D'vloper"
job: Developer
skill: Elite
Don't double encode it:
var textYAML = $('#yaml-create').val();

Wordpress blocks: async REST calls in registerBlockType edit function

I'm writing a WordPress plugin that creates a block, the block needs to pull data using a custom REST endpoint that returns, in the example below, a simple string. I'd like to include this string in the return from edit() and save() in my registerBlockType config but. I'm using fetch() to call the REST endpoint but this, obviously, is async. Any thoughts on the best way to do this appreciated, thanks:
const { registerBlockType } = wp.blocks
registerBlockType( 'daisy-views/da-test', {
title: 'Daisy Test: Test Block',
icon: 'format-gallery',
category: 'common',
attributes: {
gid: {
default: 2,
type: 'integer'
},
},
edit( props ) {
const restEP = daRestUrl + 'test'
fetch( restEP, {
body: JSON.stringify( {p: 'test param'}), // test parameters
cache: 'no-cache',
method: 'POST',
redirect: 'follow',
referrer: 'no-referrer',
headers : {
'Access-Control-Allow-Origin' : '*',
'X-WP-Nonce' : wpApiSettings.nonce,
}
})
.then( response => {
response.json()
.then( data => {
var returnValue = data.data // REST test, returns a string
console.log( 'Fetch returns: ', returnValue )
})
})
return <div>
test block edit
{/* return value from fetch here */}
</div>
},
save( props ) {
return <div>
Test Block
{/* return value from fetch here */}
</div>
}
} );
My best solution, to date, is to add a code attribute and have the fetch call fill that attribute with HTML. if fetch is called directly in the edit function there needs to be a check to prevent it from being called in an endless loop when it updates the attribute.

Promise Rejected Uncaught Data was empty

I am making a web app With Polymer. I make a POST request and then fill an object, then I'm making a databind to fill the data attribute needed in the google-chart tag I'm using.
<dom-module id="leads-chart" bind>
<template>
<google-chart
id="leadschart"
type='column'
data={{datagraph}}>
</google-chart>
</template>
<script>
Polymer({ is: "leads-chart",
properties:{
params:{
type: Object
},
command:{
type: String,
value: "SP_GetLead12Meses"
},
datagraph:{
type: Object,
computed: 'getBargraph(command,params)'
}
},
getBargraph: function(command,params){
var options = {
hostname: 'localhost',
path: '/',
port: 8081,
secure: false,
method: 'POST',
headers: {
'x-powered-by': 'HTTPClient.js'
},
'Content-Type': 'application/json'
}
var dictionary = new Object();
var outter = [];
const that = this;
var example1 = new HTTPClient(options)
example1.post("/executeGraph1?command="+ command + "&param1=" + params.user, function (err, res, body) {
body = JSON.parse(body);
outter.push(['Mes','Leads',{"role":"style"}]);
for(var k in body){
var inner = [];
inner.push(dictionary[body[k]['MES']]);
inner.push(body[k]['LEADS']);
inner.push("#00A6d4");
outter.push(inner);
}
});
return outter;
}
});
The problem is the chart is not showing any data. The browser shows the following message:
The weirdest thing is that this error at the beggining was present in rare ocations but now I get it every time I load the page. Does someone know why is it happening and how to solve it?
I have made some debugging and found out the post message is answering the request with the correct information.
the object is being filled with data but the message is still there and chart is still empty

Specify response.request.responseURL in moxios

I'm currently trying to write some functionality that requires the response.request.responseURL value to be set when axios handles the response. However, I can't seem to set this value with moxios. Here's what my test looks like:
it('resets list selection if input contents were replaced', (done) => {
component.currently_selected_list_value = 10;
component.last_called_url = 'henkiehoutman';
let input = domElt.querySelector('input');
ReactTestUtils.Simulate.change(input);
moxios.wait(() => {
let request = moxios.requests.mostRecent();
request.respondWith({
status: 200,
response: [{
customer_info_customers: ['', '', '', '', ''],
domain_info_customers: {},
}],
request: {responseURL: 'banaan'}
}).then(() => {
// The contents were replaced, so it's best to forget whatever our selection was.
expect(component.currently_selected_list_value).toEqual(-1);
done();
});
});
});
This is what my actual application looks like:
onChange (event) {
return axios.get(
this.props.ApiUrl + encodeURIComponent(event.target.value)
).then(
(response) => {
let response_url = response.request.responseURL; // This is the value I want to set manually.
if(this.shouldHandleResponse(response_url)){
this.last_called_url = response_url;
let data = response.data;
this.setState({results: data, dropdown: data.length > 0});
if ( this.currently_selected_list_value > max_index) {
this.currently_selected_list_value = max_index;
}
}
}
);
},
However, when I log what this value is, it just says undefined. And this is what the actual response.request value is (put it in a quote so it's a bit more readable):
LOG: Request{resolve: function (a) { ... }, reject: function (a) { ... }, config: Object{adapter: function mockAdapter(config) { ... }, transformRequest: Object{0: ...}, transformResponse: Object{0: ...}, timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, validateStatus: function validateStatus(status) { ... }, headers: Object{Accept: ..., X-CSRFToken: ...}, method: 'get', url: 'my_api_url/', data: undefined}, headers: Object{Accept: 'application/json, text/plain, /', X-CSRFToken: 'my_csrf_token'}, url: 'my_api_url/', timeout: 0, withCredentials: false, responseType: undefined}
This breaks my application, because a responseURL should always be defined. It looks like it's overwriting the request I defined in moxios. This is not necessarily a bad thing, because I assume it needs these things to function properly. However, it would be nice if I could add some values to this request.
So; How do I add a responseURL value to this request in moxios?
Turns out that it's not possible to set the responseURL because of the way I chained it to respondWith(). After checking this function in the moxios source code I saw that the values you pass in here really only have to do with actual data being returned, not an actual response object.
I also saw that the respondWith() function returns a Promise object, which is quite logical. I figured that I should not set anything on the Promise, but on the actual request. So I assigned the returned Promise to a promise variable and unchained the .then() part of the test. I set the request'sresponseURL after that. Then I called promise.then() again to assert that my test has passed.
Here is what I eventually went for:
it('resets list selection if input contents were replaced', (done) => {
component.currently_selected_list_value = 10;
component.last_called_url = 'henkiehoutman';
let input = domElt.querySelector('input');
ReactTestUtils.Simulate.change(input);
moxios.wait(() => {
let request = moxios.requests.mostRecent();
let promise = request.respondWith({
status: 200,
response: [{
customer_info_customers: ['', '', '', '', ''],
domain_info_customers: {},
}],
});
request.responseURL = 'banaan';
promise.then(() => {
// The contents were replaced, so it's best to forget whatever our selection was.
expect(component.currently_selected_list_value).toEqual(-1);
done();
});
});
});

Ember JS: Customizing adapter to include multiple parameters

I currently have a database with 2 objects:
Role
Permission
ONE Role can have MANY permissions. I currently have my Role adapter setup as:
export default DS.RESTAdapter.extend(DataAdapterMixin, {
namespace: 'v1',
host: ENV.APP.API_HOST,
authorizer: 'authorizer:application',
pathForType: function(type) {
return 'staff/roles';
}
});
By default, when a Permission is added to a Role, it generates this request:
Request:
PUT /v1/staff/roles/1
Body:
{
"name": "name_of_role"
"permissions": [
{
"id": "3",
"name": "name_of_permission"
},
...
]
}
I'd like to customize my adapter to produce a request that looks like this instead:
Request:
PUT /v1/staff/roles/1/permissions/3
Body:
<None>
Can someone please tell me how I can go about doing this? Updating the server api to accommodate Ember JS is unfortunately not an option.
UPDATE:
Based on Ryan's response, here's a (I'll call it messy) workaround that did the trick for me.
Open to suggestions for making this more elegant:
export default DS.RESTAdapter.extend(DataAdapterMixin, {
namespace: 'v1',
host: ENV.APP.API_HOST,
authorizer: 'authorizer:application',
pathForType: function(type) {
return 'staff/roles';
},
updateRecord: function(embestore, type, snapshot) {
var roleID = snapshot.id;
var permissionID = snapshot.adapterOptions.permissionID;
var url = ENV.APP.API_HOST + "/v1/staff/roles/" + roleID + "/permissions/" + permissionID;
return new Ember.RSVP.Promise(function(resolve, reject){
Ember.$.ajax({
type: 'PUT',
url: url,
headers: {'Authorization': 'OAUTH_TOKEN'},
dataType: 'json',
}).then(function(data) {
Ember.run(null, resolve, data);
}, function(jqXHR) {
jqXHR.then = null; // tame jQuery's ill mannered promises
Ember.run(null, reject, jqXHR);
});
});
},
});
I can't find it in the Ember documentation but there is a universal ajax method attached to adapter that you can override.
So in my adapter to fit our auth scheme I've done this:
export default DS.RESTAdapter.extend({
host: ENV.host,
ajax: function(url, method, hash){
if(hash){
if(hash.data !== undefined && hash.data !== null){
hash.data.sessionId = this.getSessionId();
}
}else {
hash = {
data: {}
};
hash.data.sessionId = this.getSessionId();
}
return this._super(url, method, hash);
},
getSessionId: function(){
return window.sessionStorage.getItem('sessionId') || {};
}
}
This attaches the sessionId to every ajax call to the server made though out the entire application.
Changing it to modify your url based on the hash arguments passed in shouldn't be an issue.
My version of ember is 2.3.2 but I'm on the latest stable(2.5.2) version of ember-data and this is still working great in case you are worried about the age of that blog post I found.

Categories