Making template html for json data - javascript

I am using t.js as a template engine in my project. How to make template for this json:
{
data: [
{
FirstName: "Test1",
LastName: "Test11"
},
{
FirstName: "Test2",
LastName: "Test22"
},
{
FirstName: "Test3",
LastName: "Test33"
}
]
}
I want to render it like
<ul>
<li>Test1,Test11</li>
<li>Test2,Test22</li>
<li>Test3,Test33</li>
</ul>
Can you suggest any other template engine along with template html for my above case which is better? I don't want to use any template engine using eval or new Func

Markup
<ul id="myList">
{{#mydata}} <li>{{=_val.FirstName}},{{=_val.LastName}}</li> {{/#mydata}}
</ul>
Javascript
var source = $("#myList").html();
var template = new t(source);
$("#myList").html(template.render({
mydata: [
{
FirstName: "Test1",
LastName: "Test11"
},
{
FirstName: "Test2",
LastName: "Test22"},
{
FirstName: "Test3",
LastName: "Test33"
}
]
}));
demo : http://jsfiddle.net/diode/c2Qhw/

Related

MongooseJS - Insert Subdocument without Validation on Document

I am using Mongoose with Javascript (NodeJS) to read/write to MongoDB. I have a Document (Parent) that has a bunch of Subdocuments (Children) in it. Both my Document and Subdocuments have validation (required: true and a function that validates that the user puts text in the field) defined in their Model.
When attempting to push a new Subdocument into the database, Mongoose rejects my push because validation fails on the Document. This has perplexed me as I am not trying to create a new Document with Subdocument, I am simply trying to push a new Subdocument into an existing Document.
Here is my (example) Mongoose Model:
const mongoose = require('mongoose');
const requiredStringValidator = [
(val) => {
const testVal = val.trim();
return testVal.length > 0;
},
// Custom error text
'Please supply a value for {PATH}',
];
const childrenSchema = new mongoose.Schema({
childId: {
type: mongoose.Schema.Types.ObjectId,
},
firstName: {
type: String,
required: true,
validate: requiredStringValidator,
},
lastName: {
type: String,
required: true,
validate: requiredStringValidator,
},
birthday: {
type: Date,
required: true,
},
});
const parentSchema = new mongoose.Schema(
{
parentId: {
type: mongoose.Schema.Types.ObjectId,
},
firstName: {
type: String,
required: true,
validate: requiredStringValidator,
},
lastName: {
type: String,
required: true,
validate: requiredStringValidator,
},
children: [childrenSchema],
},
{ collection: 'parentsjustdontunderstand' },
);
const mongooseModels = {
Parent: mongoose.model('Parent', parentSchema),
Children: mongoose.model('Children', childrenSchema),
};
module.exports = mongooseModels;
I can successfully push a new Child Subdocument into the Parent Document via the following MongoDB command:
db.parentsjustdontunderstand.update({
firstName: 'Willard'
}, {
$push: {
children: {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968" }
}
});
However, when I follow the Mongoose documentation Adding Subdocs to Arrays and try to add it via Mongoose, it fails.
For testing purposes, I am using Postman and performing a PUT request against an endpoint.
The following is req.body:
{
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
My code is:
const { Parent } = require('parentsModel');
const parent = new Parent();
parent.children.push(req.body);
parent.save();
What I get back is:
ValidationError: Parent validation failed: firstName: Path `firstName` is required...`
and it lists all of the Parent Document's validation requirements.
I could use some help on what I am doing wrong. For the record, I have looked at this answer on Stackoverflow: Push items into mongo array via mongoose but most examples I see do not show or discuss validation in their Mongoose Models.
EDIT 1
Based on feedback from #j-f, I modified my code to below (moving the body out of req.body and just creating it in code for testing purposes. When I attempt to push the update the way recommended, the record gets inserted, however, I still get a validation error thrown to console:
const parent = await Parent.findOne({firstName: 'Willard'});
const child = {
children: {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
}
parent.children.push(child);
parent.save();
ValidationError: Parent validation failed: children.12.firstName: Path `firstName` is required., children.12.lastName: Path `lastName` is required., children.12.birthday: Path `birthday` is required.
ANSWER
#J.F is correct and I am wrong.
This is incorrect:
const child = {
children: {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
}
This is correct:
const child = {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
The record gets inserted into the database and saved but since I was initiating this as a PUT request, I was not properly responding after a successful save with an HTTP 200 OK. Correct code below for the entire solution, however, keep in mind the res.status code is only necessary in this scenario because I was imitating the code via a PUT request.
Mongoose Model:
const mongoose = require('mongoose');
const requiredStringValidator = [
(val) => {
const testVal = val.trim();
return testVal.length > 0;
},
// Custom error text
'Please supply a value for {PATH}',
];
const childrenSchema = new mongoose.Schema({
childId: {
type: mongoose.Schema.Types.ObjectId,
},
firstName: {
type: String,
required: true,
validate: requiredStringValidator,
},
lastName: {
type: String,
required: true,
validate: requiredStringValidator,
},
birthday: {
type: Date,
required: true,
},
});
const parentSchema = new mongoose.Schema(
{
parentId: {
type: mongoose.Schema.Types.ObjectId,
},
firstName: {
type: String,
required: true,
validate: requiredStringValidator,
},
lastName: {
type: String,
required: true,
validate: requiredStringValidator,
},
children: [childrenSchema],
},
{ collection: 'parentsjustdontunderstand' },
);
const mongooseModels = {
Parent: mongoose.model('Parent', parentSchema),
Children: mongoose.model('Children', childrenSchema),
};
module.exports = mongooseModels;
The following is req.body:
{
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
Code is:
const { Parent } = require('parentsModel');
const parent = await Parent.findOne({firstName: 'Willard'});
parent.children.push(req.body);
parent.save((err, doc) => {
if (err) {
res.status(500).json({
message: 'Error finding active projects',
error: err,
});
} else {
res.status(200).json(doc);
}
});
You can push the children into the parent using a mongo query because into the update, the first object is to find the document where do the push.
The syntaxis is like: update({query},{update},{options}). So you are looking for a document with firstName: 'Willard' and adding the children into it.
Here everything is ok, all fields exists, the parent exists into collection so there is no problem.
But using
const parent = new Parent();
parent.children.push(req.body);
parent.save();
Your parent object is empty (unless the constructor fill all fields, but this is not a good idea I think).
If you try this:
var parent = await model.findOne({firstName: 'Willard'})
parent.children.push(req.body);
parent.save();
Then should works.
In this case, the object parent is retrieved from collection, so it contains all necessary fields.
I'm going to edit to explain better why is not thethe two queries are not the same.
Basically the child object you are trying to save has not the same structure as db.collection.update one. Note that the object child you have create to insert into collection has only one property called children. It doesn't have the necessary properties like firstName...
I'm going to use pure JS to can see what is the console.log() output and to see the differences.
Your mongo query push an object like this (translated to js language):
var array = []
array.push(
children = {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
)
console.log(array)
But you are creating the object in this way:
const child = {
children: {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
}
console.log(child)
Do you see now the difference? One object is the children itself the other object has the property children with the necessary fields.
So let's combinate the two pieces of code:
const child = {
children: {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
}
const children = {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
var array = [child,children]
console.log(array)
So, for your code, if you use:
parent.children.push(child.children);
parent.save();
should works. BUT, the best ways is not created the object children inside const child
Try using:
const child = {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
parent.children.push(child);
parent.save();

Get multiple entries for parent object foreach child (this child is array) object within that parent

I have 2 classes where 1 class is an array object of other class.
export class Certificate {
public certType: string;
public certBeginDate: Date;
}
export class User {
firstName: string;
lastName: string;
userGroup: string;
certificates: Array<Certificate>;
email: string;
username: string;
}
I get an object like this :
userdata: {
{
firstName: "name1",
lastName: lname1,
userGroup: ug1,
certificates: {
{
certType: cer1;
certBeginDate: Date1;
},
{
certType: cer2;
certBeginDate: Date2;
}
};
email: email1;
username: uname1;
},
{
firstName: "name2",
lastName: lname2,
userGroup: ug2,
certificates: {
{
certType: cer21;
certBeginDate: Date21;
}
},
email: email2;
username: uname2;
}
}
which I need to convert into :
userdatatoexport: {
{
firstName: "name1",
lastName: lname1,
userGroup: ug1,
certType: cer1;
certBeginDate: Date1;
email: email1;
username: uname1;
},
{
firstName: "name1",
lastName: lname1,
userGroup: ug1,
certType: cer2;
certBeginDate: Date2;
email: email1;
username: uname1;
},
{
firstName: "name2",
lastName: lname2,
userGroup: ug2,
certType: cer21;
certBeginDate: Date21;
email: email2;
username: uname2;
}
}
for this tried multiple ways but I am not able to concatenate the users object with the certificates in a proper way. the object I need to pass to export it out.
let a1:any[];
this.state.userdata.map((user, index) => user.certificates.length !== 0 ? (user.certificates.map((cer, index) => a1.push({ user + cer })) ) :a1.push(user));
In this above solution I am getting error while push(user + cer). when I hover over the user in that it is showing (property)user as :number type it actually should be of :User type.
I need to create multiple entries for users data based on the certificates count with individual certificates data merged with the respective user data.
Edit 1 :
Using FlatMap() is resolving the issue but flatmap() is not supported on IE and Edge. So I tried to implement the logic behind the flatmap() using Map() and reduce() functions.
let res1 = UserData.map(User => {
return User.certificates.length !== 0 ? User.certificates.map(cer => {
let o = Object.assign({}, User, cer); return o;
}) : Object.assign({}, User, new Certificate())
})
In res1 I am getting an array of arrays of type [User & Certificate]. I just need to convert that into simple array of type [User & Certificate]. For I tried to user reducer() with concat() as :res1.reduce((acc, val) => acc.concat(val), []);
this statement works fine in the console log when I tried to debug the code.
but this statement is throwing compile errors as "concat() is not available on acc."
How can I convert :
[[(user1 & cert11),(user1 & cert12)],[(user2 & cert1)], (user3 & cert3)] to
[(user1 & cert11),(user1 & cert12),(user2 & cert1), (user3 & cert3) ].
You can use flatMap
var userdata = [
{
firstName: "name1",
certificates: [
{
certType: 'a'
},
{
certType: 'b'
}
],
},
{
firstName: "name2",
certificates: [
{
certType: 'c'
}
],
}
];
let res = userdata.flatMap(user=>{
return user.certificates.map(cert=>{
let o = Object.assign({}, user, cert);
delete o.certificates;
return o;
})
})
console.log('got ', JSON.stringify(res,null,1))
As noted by HMR, by destructuring we get to the same result as well
var userdata = [
{
firstName: "name1",
certificates: [
{
certType: 'a'
},
{
certType: 'b'
}
],
},
{
firstName: "name2",
certificates: [
{
certType: 'c'
}
],
}
];
let res = userdata.flatMap(({certificates,...user})=>{
return certificates.map(cert=>{
return {...cert, ...user};
})
})
console.log('got ', JSON.stringify(res,null,1))

Pass value to Json schema Definition

I'm using AJV Schema validator on NodeJS and wish to add userID from sessionObject to every incoming payload so that I can store userID for each transaction.
I wish to know if that can be done in json schemas.
sample Incoming Client payload -
Client: {
Client_Id: 12,
ClientName: 'jon',
Address: [{
Address_Id: 22,
Street: 'Sesimi Street',
City: 'Mumbai'
}
],
Contact: [{
Contact_Id: 23,
Phone: 11111111,
Email: "jon#doe.com"}]
Desired object post schema Validation -
Client: {
Client_Id: 12,
ClientName: 'jon',
UserId: 12121,
Address: [{
Address_Id: 22,
Street: 'Sesimi Street',
City: 'Mumbai',
UserId: 12121
}
],
Contact: [{
Contact_Id: 23,
Phone: 11111111,
Email: "jon#doe.com",
UserId: 12121
}]
Since incoming payloads are huge, I believe it would be best to do assignments at schema validation point instead of doing recursive operations inside of my application. I'm open to suggestions.
Thank you
You can try useDefaults feature of AJV.
var ajv = new Ajv({ useDefaults: true });
var schema = {
"type": "object",
"properties": {
"ClientName": { "type": "string" },
"UserId": { "type": "integer", "default": 12121 }
}
};
var data = { "ClientName": "jon" };
var validate = ajv.compile(schema);
console.log(validate(data)); // true
console.log(data); // { "ClientName": "jon", "UserId": 12121 }
To have flexibility on default value you can use dynamicDefaults with callback function. Example:
var uuid = require('uuid');
function getUuid(args) {
var version = 'v' + (arvs && args.v || 4);
return function() {
return uuid[version]();
};
}
var definition = require('ajv-keywords').get('dynamicDefaults').definition;
definition.DEFAULTS.uuid = getUuid;
var schema = {
dynamicDefaults: {
id1: 'uuid', // v4
id2: { func: 'uuid', v: 4 }, // v4
id3: { func: 'uuid', v: 1 } // v1
}
};
Thankyou #vearutop for your answer helped me solve my problem.
All I did was use a custom function that returns UserId from sessionObject
var Ajv = require("ajv");
var ajv = new Ajv({useDefaults: true,});
require("ajv-keywords")(ajv);
var definition = require('ajv-keywords/keywords/dynamicDefaults').definition;
definition.DEFAULTS.getuser = getuser;
function getuser() {
return sessionObject.UserId;
}
var schema = {
dynamicDefaults: {
user: 'getuser'
},
properties: {
user: {}
}
};

Enyo different collection with same model kind

I have been trying to create two collection with a common model kind. I am getting the following error:
"Uncaught enyo.Store.addRecord: duplicate record added to store for kind app.ImageModel with primaryKey set to id and the same value of 67774271 which cannot coexist for the kind without the ignoreDuplicates flag of the store set to true ".
Following are the two collection i have defined...
enyo.kind({
name: "app.FeatureCollection",
kind: "enyo.Collection",
model: "app.ImageModel",
defaultSource: "appF",
...
...
});
enyo.kind({
name: "app.SearchCollection",
kind: "enyo.Collection",
model: "app.ImageModel",
defaultSource: "appS",
...
...
});
And the model which i am using is as follows:
enyo.kind({
name: "app.ImageModel",
kind: "enyo.Model",
readOnly: true,
....
....
});
At one point i am setting like this:
this.set("data", new app.FeatureCollection());
and in another,
this.set("data", new app.SearchCollection());
I am not able to find out what could generate the error. I even tried to set "ignoreDuplicates" to true in model...but still the error comes. Any suggestion where i could be going wrong.
The ignoreDuplicates flag is expected to be set on enyo.Store and not enyo.Model:
enyo.store.ignoreDuplicates = true;
Are you using the fetch method of enyo.Collection to retrieve your data? If so, you might consider setting the strategy property to merge in your fetch call so that you have a single record for each unique image from your dataset, i.e.:
myCollection.fetch({strategy: "merge", success: function(rec, opts, res) {
// do something after data is retrieved
}});
I'm not seeing a problem with the pieces of code you provided. I created a sample on jsFiddle and it works as expected.
http://jsfiddle.net/z7WwZ/
Maybe the issue is in some other part of your code?
enyo.kind({
name: "app.FeatureCollection",
kind: "enyo.Collection",
model: "app.MyModel"
});
enyo.kind({
name: "app.SearchCollection",
kind: "enyo.Collection",
model: "app.MyModel"
});
enyo.kind({
name: "app.MyModel",
kind: "enyo.Model",
readOnly: true,
defaults: {
firstName: "Unknown",
lastName: "Unknown"
}
});
enyo.kind({
name: "App",
components: [],
bindings: [],
create: enyo.inherit(function (sup) {
return function () {
sup.apply(this, arguments);
this.collection1 = new app.FeatureCollection(this.data1);
enyo.log("Collection1(0) >>> " + this.collection1.at(0).get("lastName"));
this.collection1.at(0).set("lastName", "Smith");
enyo.log("Collection1(0) >>> " + this.collection1.at(0).get("lastName"));
this.collection2 = new app.SearchCollection(this.data2);
enyo.log("Collection2(0) >>> " + this.collection2.at(0).get("lastName"));
this.collection1.at(0).set("lastName", "Jones");
enyo.log("Collection2(0) >>> " + this.collection1.at(0).get("lastName"));
};
}),
data1: [{
firstName: "Hall",
lastName: "Caldwell"
}, {
firstName: "Felicia",
lastName: "Fitzpatrick"
}, {
firstName: "Delgado",
lastName: "Cole"
}],
data2: [{
firstName: "Alejandra",
lastName: "Walsh"
}, {
firstName: "Marquez",
lastName: "James"
}, {
firstName: "Barr",
lastName: "Lott"
}]
});
new App().renderInto(document.body);

Backbone.js adding to Collection

In Backbone, I have a collection which is populated with some JSON data which looks like below.
[
{
"test1": {
"fistName": "test",
"lastName": "example"
},
"test2": {
"fistName": "test",
"lastName": "example"
}
},
{
"test1": {
"fistName": "test",
"fistName": "example"
},
"test2": {
"fistName": "test",
"fistName": "example"
}
},
]
Currently im trying to add a new model to the collection holding data like the above.
This is the model.
Test = Backbone.Model.extend({
defaults : {
test1: {
firstName: null,
lastName: null
},
test2: {
firstName: null,
lastName: null
}
},
});
Below is what I am trying
var test = new Test({test1: {firstName: $("#test1 option:selected").val(), score: $("#test1lastName").val()}}, {test2: {firstName: $("#test2 option:selected").val(), score: $("#test2lastName").val()}});
myCollection.add(test);
However doing this only populates test1 data and not test2 data. What would be the correct way to add both test1 and test2 data into the model, which could then be added to the collection.
Thanks
UPDATE
Just to clarify, test 1 and 2 are not separate objects, they are relevant to each other and need to be in the same model
Edit, depending on how your model is defined, if you format it as below you might able to debug a little better.
var test = new TFS.Test({
test1: {
firstName: $("#test1 option:selected").val(),,
lastName: '', // code for last name?
score: $("#test1lastName").val()
},
test2: {
firstName: $("#test2 option:selected").val(),
lastName: '',
score: $("#test2lastName").val()
}
});
myCollection.add(test);
I might be able to offer you a little more help if you give a better view of the entire action/process - i.e. what is triggering the creation of these models? Could there be a problem with jQuery, and your document not being ready?

Categories