Why don't default nested Polymer values work? - polymer

I am using the latest 2.0-preview version of Polymer. I'd like to set default properties, and the Polymer documentation describes how to do it in Polymer 1.x. I was unable to find any changes in this approach for v2.0. But it seems to only work for primitive properties and not objects:
"use strict";
class NewElement extends Polymer.Element {
static get is() {
return 'new-element';
}
static get config() {
return {
properties: {
user: {
// type: Object, <-- doesn't help anyway
firstName: {
type: String,
value: "John",
// observer: '_callObserver' <-- FYI observers don't work properly too if this usage...
},
lastName: {
type: String,
value: "Doe"
}
},
position: {
type: String,
value: "Waiter" // <-- will set a high-level default value properly correctly
}
},
// observers: [
// '_callObserver(user.*)' <-- ...but works using this approach
// ]
}
}
constructor() {
super();
console.dir(this); // <-- see screenshots below
// this.user = { firstName: "John", lastName: "Doe" }; <-- works if initialized manually
}
}
customElements.define(NewElement.is, NewElement);
As you can see here there is a getter, and when I click on it, I see that user field is undefined.
What am I doing wrong?

It looks like you're trying to nest property declarations, which is not supported. You can declare an object property that contains subproperties (not property declarations that have type, observer, etc.).
The user property declaration:
properties: {
user: {
type: Object,
firstName: {
type: String,
value: "John",
},
lastName: {
type: String,
value: "Doe"
}
},
},
should actually look like this:
properties: {
user: {
type: Object,
value: function() {
return {
firstName: "John",
lastName: "Doe"
};
}
},
},
codepen

Related

How to map an object from JSON file to another object?

Here is my json file
{
"data": [
{
"firstName": "Tom",
"lastName": "Yoda",
"type": "guest",
"id": "0",
"gender": m,
"data": { "age": 26, "born": "UK" }
},
]
}
This data array could have more entries.
I have to map the values into an interface which looks like:
InterfacePerson {
id: string;
title: string;
firstName: string;
lastName: string;
age: string;
location: string;
}
I am unable to change the interface. So I'm trying to do some pseudo coding.
const list;
list = convertToInterfacePerson = (value): Array<InterfacePerson> => {
return {
id: value.id,
title: if(value.gender === "m")? "Mr" : "Mrs",
firstName: value.firstName,
lastName: value.lastName,
age: value.data.age,
//...
}
}
I think you were trying to use a conversion mapping function called convertToInterfacePerson but you hadn't set it up yet (separately from trying to use it). The code below shows it declared and used within a map Array method call. I believe this resolves the error(s) you were getting.
// Copied in the JSON for demonstration
const sourceJson = {
"data": [
{
"firstName": "Tom",
"lastName": "Yoda",
"type": "guest",
"id": "0",
"gender": "m",
"data": { "age": 26, "born": "UK" }
},
]
};
// Declared the InterfacePerson interface
interface InterfacePerson {
id: string;
title: string;
firstName: string;
lastName: string;
age: string;
location: string;
}
// Declared the conversion mapping function (optional parameter typing included)
const convertToInterfacePerson = (value: { firstName: string, lastName: string, type: string, id: string, gender: string, data: { age: number, born: string } }): InterfacePerson => {
return {
id: value.id,
// Removed the `if` statement due to ternary conditional
title: ((value.gender === "m") ? "Mr" : "Mrs"),
firstName: value.firstName,
lastName: value.lastName,
// Wrapped the value.data.age in a string conversion
age: String(value.data.age),
location: value.data.born
};
}
// Declared and assigned the list based on the returned array from the mapping function (each element is applied in the `convertToInterfacePerson` function)
const list = sourceJson.data.map(convertToInterfacePerson);
// Show the result of the conversion
console.log(JSON.stringify(list, null, 2));
And for a live example, check out this TypeScript Playground script containing this solution.

Json Schema validate reference property on same object

Using JSON Schema 7 to perform validations
Is the below validation possible using json schema.
{
properties : [{name: "a"}, {name: "b"}, {name: "c"}],
rules : [{ prop : ["a","b"] }, { prop : ["a"] }, {prop: ["c"]}]
}
The "prop" property in object is dependent values in properties.
ie only of "properties.name" exists then that value can be added to the "prop" array
Note:
The "properties" array can have any object of type {name : }
"name" can have any possible string, which i don't know beforehand
I have been going through documentation, but can find a answer.
Is this validation not supported in Json Schema yet?
You can't do it with a static JSON schema.
To archive it you would need a dynamic schema validation, but this could be dangerous to code injection from malicious users:
const Ajv = require('ajv')
const ajv = new Ajv({ allErrors: true, jsonPointers: true })
const data = {
properties: [{ name: 'a' }, { name: 'b' }, { name: 'c' }],
rules: [{ prop: ['a', 'b'] }, { prop: ['a', 'zz'] }, { prop: ['c'] }]
}
const validProp = data.properties.map(_ => _.name)
const schema = {
type: 'object',
required: ['properties', 'rules'],
properties: {
properties: {
type: 'array',
items: {
type: 'object',
required: ['name'],
properties: {
name: { type: 'string' }
}
}
},
rules: {
type: 'array',
items: {
type: 'object',
required: ['prop'],
properties: {
prop: {
type: 'array',
uniqueItems: true,
items: {
type: 'string',
enum: validProp // here happen the validation
}
}
}
}
}
}
}
const isValid = ajv.validate(schema, data)
if (!isValid) {
console.log(ajv.errors)
}

NestJS Swagger: Describe Map inside ApiProperty Decorator

I have an NestJS API in front of an InfluxDB. In the API I want to add property description via the ApiProptery decorator from nestjs/swagger.
My Problem here is that I don't know how to create a proper description for a map.
Here is my model:
import { Precision } from '../shared/enums';
import { IsEnum, IsInt, IsOptional } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '#nestjs/swagger';
import { IsPrimitive } from '../shared/decorator/decorators';
export class CreateMeasurementDto {
#IsOptional()
#IsInt()
#ApiPropertyOptional()
timestamp: number;
#IsOptional()
#IsEnum(Precision)
#ApiPropertyOptional({ enum: Precision })
precision: Precision;
#ApiProperty({
description:
'Key/value pairs; values can be of type string, boolean or number.',
type: Map,
})
#IsPrimitive()
datapoints: Map<string, string | boolean | number>;
}
What I get in the SwaggerUi schema section is this:
CreateMeasurementDto{
timestamp number
precision string
Enum:[ s, ms, u, ns ]
datapoints* Map {
}
}
I want at least give an example or describe an element of the map. Both would be awesome.
The map is allowed to have strings as keys, while values can be string, boolean or number.
Here is a possible payload, that would be accepted:
{
"precision": "s",
"datapoints": {
"voltage": 123.6456,
"current": 123
}
}
With the latest version of nestjs/swagger which is version 4, you can define Raw Definitions Swagger Documentations
#ApiProperty({
type: 'object',
additionalProperties: {
oneOf: [
{ type: 'string' },
{ type: 'number' },
{ type: 'boolean' }
]
}
})
datapoints: Map<string, string | boolean | number>;

Angular2 & Typescript - Create object from nested JSON

I have a class which has multiple interfaces inside of it to model a JSON data. For example:
interface A {
id: number;
}
interface B {
name: string;
surname?: string;
}
class MyClass implements A {
people: B[];
notes: string[];
function1(){...}
function2(){...}
}
And I have a JSON in the same structure:
{
id: 1,
people: [
{
name: "john"
},
{
name: "alice",
surname: "smith"
}
],
notes: [ "Very important top secret note" ]
}
Can I create an instance of MyClass from this JSON directly?
Your data structure is almost the same as your class, you'd have to add an id property to the class
class MyClass implements A {
id: number;
// ....
}
The problem is if you were trying to do something like this:
let data: MyClass = {
id: 1,
people: [
{
name: "john"
},
{
name: "alice",
surname: "smith"
}
],
notes: [ "Very important top secret note" ]
}
This won't work because your json does not have the methods (function1, function2).
One solution would be to really instantiate the MyClass and pass the json, or have a constructor method for that like
class MyClass {
static createFrom(jsonData: A & B): MyClass {
// create the objct and return
}
}
Or, you could create a variable of that type by combining an existing instance of the class and spreading the json.
Like so:
let json = {
id: 1,
people: [
{
name: "john"
},
{
name: "alice",
surname: "smith"
}
],
notes: ["Very important top secret note"]
}
const c = new MyClass();
let mClass: MyClass = {...json, function1: c.function1, function2: c.function2 };
mClass.function1();
Link to playground

Derived attribute absent in JSON response in Sails.js

I'm writing an API for users in an example app. The api/models/User-file looks as follows:
module.exports = {
attributes: {
firstName: {
type: 'string',
required: true
},
lastName: {
type: 'string',
required: true
},
fullName: function () {
return this.firstName + ' ' + this.lastName;
}
}
};
However, when I find all my users, the derived attribute is nowhere to be found in the response:
[
{
"firstName": "Marlon",
"lastName": "Brando",
"createdAt": "2015-09-13T10:05:15.129Z",
"updatedAt": "2015-09-13T10:05:15.129Z",
"id": 8
},
{
"firstName": "Bjoern",
"lastName": "Gustavsson",
"createdAt": "2015-09-13T10:05:36.221Z",
"updatedAt": "2015-09-13T10:05:36.221Z",
"id": 10
},
{
"firstName": "Charlie",
"lastName": "Sheen",
"createdAt": "2015-09-13T10:06:59.999Z",
"updatedAt": "2015-09-13T10:06:59.999Z",
"id": 11
}
]
Am I missing something, or is it simply not possible to derive attributes like this?
When you are set attributes in Model with function it doesn't mean that it will be executed in resulting attribute. It means that you can call this function in your code. For instance, I have exactly your User model. I can make in my code smth like this:
// api/controllers/UserController.js
module.exports = {
index: function(req, res) {
User
.create({firstName: req.param('firstName'), lastName: req.param('lastName')})
.then(function(user) {
console.log(user.fullName());
return user;
})
.then(res.ok)
.catch(res.negotiate);
}
};
If you want to make it like a dynamic attribute, then you should take a look at toJSON method in your model. You can override it and implement your own logic. I think it will looks like this in your case:
// api/models/User.js
module.exports = {
attributes: {
firstName: {
type: 'string'
},
lastName: {
type: 'string'
},
fullName: function() {
return [this.firstName, this.lastName].join(' ');
},
toJSON: function() {
var obj = this.toObject();
obj.fullName = this.fullName();
return obj;
}
}
};
I didn't check this code but think that should work. You can play around with toJSON method and see what you got. Ping me in comments if code doesn't work.