How can I set polymer property attribute value and passing attribute value into another polymer component property? - ajax

I have below piece of code which I am using to call http request using iron ajax with polymer so passing the value of body and last-response using polymer properties.as we can see here we have requestBody polymer property in this we are returning no of values in requestBody all values are hardcoded like start and end and name under tag.
<px-vis-timeseries
width="1000"
height="250"
margin='{"top":30,"bottom":60,"left":65,"right":65}'
register-config='{"type":"vertical","width":200}'
selection-type="xy"
chart-data="{{ltuchartData}}"
series-config="[[LTUseriesConfig]]"
chart-extents='{"x":["dynamic",1619712],"y":[0,100]}'
event-data='[{"id":"333","time":15697128,"label":"test"}]'
x-axis-config='{"title":"Time"}'
y-axis-config='{"axis1":
{"title":"Remaining","titleTruncation":false,"unit":"%"}}'>
</px-vis-timeseries>
<iron-ajax
id="Request"
method="POST"
content-type="application/json"
auto
url="/api/series/v1/points"
last-response="{{Data123}}"
body="{{requestBody}}">
</iron-ajax>
Polymer({
is: 'test-view',
behaviors: [GlobalsBehaviour],
properties: {
uri: {
type: String,
observer: '_uriChanged'
},
requestBody:{
type: Object,
value: function() {
return {
"start": 11111,
"end": 123333,
"tags": [
{
"name" : "/asset/India/rotor",
}
]
};
}
},
Data123:{
type: Object,
observer: '_formateData'
},
observers: [
'_uriChanged(globals.uri)'
],
_uriChanged: function(uri) {
this.set('requestBody.tags.0.name', uri);
this.$.Request.generateRequest();
}
Now Below are the queries with respect to above code .
I want to set end attribute value (which is defined in requestBody property value )dynamically based on the uri for that I tried like : this.set('requestBody.end', "1113444"); in _uriChanged, But it didn't work.
I want to pass this end attribute value dynamically in above px-vis-timeseries polymer component's property that is:
chart-extents='{"x":["dynamic",1619712],"y":[0,100]}'
event-data='[{"id":"333","time":15697128,"label":"test"}]'
in above properties I want to pass end attribute value like :
in chart-extents at the place of "1619712" I want to pass "end" + 2*50000
in event-data at the place of "15697128" I want to pass "end" + 50000
for that also i tried like this chart-extents = '{"x":["dynamic" , {{requestBody.end}}] , ,"y":[0,100]}'
now I have set end attribute value in requestBody computed function that is (_getRequestBody) based on my requirement .Now my problem is I want to get this end attribute value in my another computed functio(n of _chartExtents that is (_getChartExtents) I want pass this end attirbute value (which we will get from request body ) to xDynamic (which is the attribute of chartExtents)
As I wanted to pass uri value in name attribute which is defined in requestBody property for that I am setting like
this.set('requestBody.tags.0.name', uri); in _urichanged callback which is working fine now my problem is while defining or declaring polymer property named as requestBody i dont want to pass any hardcoded value in name attribute for that i tried "name": "" and "name" : this.uri,and "name" : uri ,but not able to get value.
Note: uri is coming from another polymer component and in some case its coming from global set variable.
How can I declare name attribute value without passing any hardcoded value?

I want to set end attribute value (which is defined in requestBody property value )dynamically ...
Not a satisfactory answer, but it should work as Polymer does dirty checking. Polymer have sometimes trouble updating properties, but not in this case, so try to override dirty checking by nullifying the element first.
_uriChanged: function(uri) {
if (this.requestBody.start) {
var clonedObj = JSON.parse(JSON.stringify(this.requestBody);
clonedObj.tags.0.name = uri;
this.set('requestBody', {});
this.set('requestBody', clonedObj);
this.$.Request.generateRequest();
}
Again, this shouldn't be needed. I would most of all make requestBody a computed value instead of setting specific values,
properties: {
requestBody:{
type: Object,
computed: '_getRequestBody(uri)'
},
// Other properties, like uri
}
// Other javascript methods
_getRequestBody: function(uri) {
var defaultURI = 123333; // I would make this a property or add a default value to 'uri'
uri = (uri) ? uri : defaultURI;
return {
"start": 11111,
"end": uri, // Here's the change
"tags": [
{
"name" : "/asset/India/rotor",
}
]
};
},
Note that computed will run no matter if the properties (uri, in this case) are defined or not. Sometimes, the order of the properties are important when using event handlers (observers) so place those last in properties.
i want to pass this end attribute value dynamically...
chart-extents='{"x":["dynamic",1619712],"y":[0,100]}'
You shouldn't pass variables like that but instead use something like chart-extents='[[myObject]]'; However, for this specific solution one of the keys depends on another variable (the object requestBody in this case).
chart-extents="[[_getChartExtents(requestBody.end)]]"
---
// Other javascript methods
_getChartExtents: function(xDynamics) {
return {"x":["dynamic",xDynamics],"y":[0,100]};
},
The _ before the method name is just a programming habit of mine, so I can see that the methods and properties aren't used by other elements.
as i wanted to pass uri value in name attribute which is defined in requestBody property for that i am setting like this.set('requestBody.tags.0.name', uri);
Just extend answer 1.
_getRequestBody: function(uri) {
var defaultURI = 123333; // I would make this a property or add a default value to 'uri'
uri = (uri) ? uri : defaultURI;
return {
"start": 11111,
"end": uri,
"tags": [
{
"name" : uri, // Here's the change
}
]
};
},

Related

AWS CDK - Can I Pass LambdaInvoke's InputPath Prop Multiple JSON Paths?

I find new LambdaInvoke requires the inputPath to be a string, so whether I need to pass the event an object from multiple places, I need a Pass state to make it happen.
this.organiseTheArrayAndId = new Pass(this, "Organise the Array and Id Together In One Object", {
parameters: {
"array": JsonPath.stringAt("$.productIdsArray"),
"value": JsonPath.numberAt("$.productId.id")
},
resultPath: "$.organiseTheArrayAndId",
});
this.augmentProductIdArray = new LambdaInvoke(this, "Add the Product ID To The Array", {
lambdaFunction: lambdaFunctionLocation,
inputPath: "$.organiseTheArrayAndId",
});
Is there a more efficient way?
The LambdaInvoke task construct's payload property lets you customize the input your function receives when invoked:
payload: sfn.TaskInput.fromObject({
array: JsonPath.stringAt("$.productIdsArray"),
value: JsonPath.numberAt("$.productId.id")
}),

Is there a way to get a structure of a Strapi CMS Content Type?

A content-type "Product" having the following fields:
string title
int qty
string description
double price
Is there an API endpoint to retrieve the structure or schema of the "Product" content-type as opposed to getting the values?
For example: On endpoint localhost:1337/products, and response can be like:
[
{
field: "title",
type: "string",
other: "col-xs-12, col-5"
},
{
field: "qty",
type: "int"
},
{
field: "description",
type: "string"
},
{
field: "price",
type: "double"
}
]
where the structure of the schema or the table is sent instead of the actual values?
If not in Strapi CMS, is this possible on other headless CMS such as Hasura and Sanity?
You need to use Models, from the link:
Link is dead -> New link
Models are a representation of the database's structure. They are split into two separate files. A JavaScript file that contains the model options (e.g: lifecycle hooks), and a JSON file that represents the data structure stored in the database.
This is exactly what you are after.
The way I GET this info is by adding a custom endpoint - check my answers here for how to do this - https://stackoverflow.com/a/63283807/5064324 & https://stackoverflow.com/a/62634233/5064324.
For handlers you can do something like:
async getProductModel(ctx) {
return strapi.models['product'].allAttributes;
}
I needed the solution for all Content Types so I made a plugin with /modelStructure/* endpoints where you can supply the model name and then pass to a handler:
//more generic wrapper
async getModel(ctx) {
const { model } = ctx.params;
let data = strapi.models[model].allAttributes;
return data;
},
async getProductModel(ctx) {
ctx.params['model'] = "product"
return this.getModel(ctx)
},
//define all endpoints you need, like maybe a Page content type
async getPageModel(ctx) {
ctx.params['model'] = "page"
return this.getModel(ctx)
},
//finally I ended up writing a `allModels` handler
async getAllModels(ctx) {
Object.keys(strapi.models).forEach(key => {
//iterate through all models
//possibly filter some models
//iterate through all fields
Object.keys(strapi.models[key].allAttributes).forEach(fieldKey => {
//build the response - iterate through models and all their fields
}
}
//return your desired custom response
}
Comments & questions welcome
This answer pointed me in the right direction, but strapi.models was undefined for me on strapi 4.4.3.
What worked for me was a controller like so:
async getFields(ctx) {
const model = strapi.db.config.models.find( model => model.collectionName === 'clients' );
return model.attributes;
},
Where clients is replaced by the plural name of your content-type.

Mocha and Chai: JSON contains/includes certain text

Using Mocha and Chai, I am trying to check whether JSON array contains a specific text. I tried multiple things suggested on this site but none worked.
await validatePropertyIncludes(JSON.parse(response.body), 'scriptPrivacy');
async validatePropertyIncludes(item, propertyValue) {
expect(item).to.contain(propertyValue);
}
Error that I getting:
AssertionError: expected [ Array(9) ] to include 'scriptPrivacy'
My response from API:
[
{
"scriptPrivacy": {
"settings": "settings=\"foobar\";",
"id": "foobar-notice-script",
"src": "https://foobar.com/foobar-privacy-notice-scripts.js",
}
You can check if the field is undefined.
If field exists in the JSON object, then won't be undefined, otherwise yes.
Using filter() expresion you can get how many documents don't get undefined.
var filter = object.filter(item => item.scriptPrivacy != undefined).length
If attribute exists into JSON file, then, variable filter should be > 0.
var filter = object.filter(item => item.scriptPrivacy != undefined).length
//Comparsion you want: equal(1) , above(0) ...
expect(filter).to.equal(1)
Edit:
To use this method from a method where you pass attribute name by parameter you can use item[propertyName] because properties into objects in node can be accessed as an array.
So the code could be:
//Call function
validatePropertyIncludes(object, 'scriptPrivacy')
function validatePropertyIncludes(object, propertyValue){
var filter = object.filter(item => item[propertyValue] != undefined).length
//Comparsion you want: equal(1) , above(0) ...
expect(filter).to.equal(1)
}

GraphQL: how to have it return a flexible, dynamic array, depending on what the marketeer filled in? [duplicate]

We are in the situation that the response of our GraphQL Query has to return some dynamic properties of an object. In our case we are not able to predefine all possible properties - so it has to be dynamic.
As we think there are two options to solve it.
const MyType = new GraphQLObjectType({
name: 'SomeType',
fields: {
name: {
type: GraphQLString,
},
elements: {
/*
THIS is our special field which needs to return a dynamic object
*/
},
// ...
},
});
As you can see in the example code is element the property which has to return an object. A response when resolve this could be:
{
name: 'some name',
elements: {
an_unkonwn_key: {
some_nested_field: {
some_other: true,
},
},
another_unknown_prop: 'foo',
},
}
1) Return a "Any-Object"
We could just return any object - so GraphQL do not need to know which fields the Object has. When we tell GraphQL that the field is the type GraphQlObjectType it needs to define fields. Because of this it seems not to be possible to tell GraphQL that someone is just an Object.
Fo this we have changed it like this:
elements: {
type: new GraphQLObjectType({ name: 'elements' });
},
2) We could define dynamic field properties because its in an function
When we define fields as an function we could define our object dynamically. But the field function would need some information (in our case information which would be passed to elements) and we would need to access them to build the field object.
Example:
const MyType = new GraphQLObjectType({
name: 'SomeType',
fields: {
name: {
type: GraphQLString,
},
elements: {
type: new GraphQLObjectType({
name: 'elements',
fields: (argsFromElements) => {
// here we can now access keys from "args"
const fields = {};
argsFromElements.keys.forEach((key) => {
// some logic here ..
fields[someGeneratedProperty] = someGeneratedGraphQLType;
});
return fields;
},
}),
args: {
keys: {
type: new GraphQLList(GraphQLString),
},
},
},
// ...
},
});
This could work but the question would be if there is a way to pass the args and/or resolve object to the fields.
Question
So our question is now: Which way would be recommended in our case in GraphQL and is solution 1 or 2 possible ? Maybe there is another solution ?
Edit
Solution 1 would work when using the ScalarType. Example:
type: new GraphQLScalarType({
name: 'elements',
serialize(value) {
return value;
},
}),
I am not sure if this is a recommended way to solve our situation.
Neither option is really viable:
GraphQL is strongly typed. GraphQL.js doesn't support some kind of any field, and all types defined in your schema must have fields defined. If you look in the docs, fields is a required -- if you try to leave it out, you'll hit an error.
Args are used to resolve queries on a per-request basis. There's no way you can pass them back to your schema. You schema is supposed to be static.
As you suggest, it's possible to accomplish what you're trying to do by rolling your own customer Scalar. I think a simpler solution would be to just use JSON -- you can import a custom scalar for it like this one. Then just have your elements field resolve to a JSON object or array containing the dynamic fields. You could also manipulate the JSON object inside the resolver based on arguments if necessary (if you wanted to limit the fields returned to a subset as defined in the args, for example).
Word of warning: The issue with utilizing JSON, or any custom scalar that includes nested data, is that you're limiting the client's flexibility in requesting what it actually needs. It also results in less helpful errors on the client side -- I'd much rather be told that the field I requested doesn't exist or returned null when I make the request than to find out later down the line the JSON blob I got didn't include a field I expected it to.
One more possible solution could be to declare any such dynamic object as a string. And then pass a stringified version of the object as value to that object from your resolver functions. And then eventually you can parse that string to JSON again to make it again an object on the client side.
I'm not sure if its recommended way or not but I tried to make it work with this approach and it did work smoothly, so I'm sharing it here.

UI Router: get params of "to" and "from" state with $transitions service

I'm trying to use $transitions service instead of $stateParams like there for listening on state changing, but can't get state params. I'm using property of StateObject, but instead of getting for example {id: 123}, i got {id: e}, where e is a object in which i can't find a value. Anybody help with this ?
$transitions.onStart({ }, function(trans) {
console.log(trans.$from().params);
}
I noticed that trans.params() return "to" state params.
trans.$from().params will get you from state parameters declaration.
trans.params('from') will get you their actual values
Probably what you need is:
$transitions.onStart({ }, function(trans) {
console.log(trans.params('from'));
}
Please refer to documentation here
State params
https://ui-router.github.io/ng1/docs/latest/interfaces/state.statedeclaration.html#params
Transition params
https://ui-router.github.io/ng1/docs/latest/classes/transition.transition-1.html#params

Resources