FORM.IO - Render/Re-build from a variable - formio

I'm doing some tests with https://unpkg.com/formiojs#latest/dist/formio.full.min.js
I was able to integrate the constructor in my application and save the generated JSON in a table.
Now I want to bring that JSON and be able to edit or render the form but I'm not doing something right.
This is my code:
window.onload = function () {
var jsonForm1 = document.getElementById ("value_forn_1"). value;
console.log (jsonForm1);
var builder = new Formio.builder (document.getElementById ("edit"), jsonForm1, {});
builder.then (function (form) {
form.on ("change", function (e) {
console.log ("builder");
var jsonSchema = JSON.stringify (form.schema, null, 4);
console.log (jsonSchema);
$ ("# value_forn_1"). val (jsonSchema);
});
});
};
value_forn_1 is the textarea containing the JSON retrieved from my table
the console.log (jsonForm1) shows me the JSON of the textarea by console
But if I want to pass the variable jsonForm1 from inside Formio.builder, I get the error:
Uncaught TypeError: Cannot read properties of null (reading '1')
4)On the other hand, if I directly assign the JSON to jsonForm1:
var jsonForm1 = { "components": [ { "label": "Text Field", "tableView": true, "key": "textField", "type": "textfield", "input": true }, { "label": "Text Area", "autoExpand": false, "tableView": true, "key": "textArea", "type": "textarea", "input": true } ] };
The rendering works ....
What am I doing wrong?

I think you already answered your own question but the schema in the jsonForm1 variable should be parsed into a JSON object to be passed into the Formio.builder function.
var jsonForm1 = JSON.parse(document.getElementById ("value_forn_1").value);
Additionally you can check out their sandbox. It's been very helpful working with the js library.
Sandbox:
https://formio.github.io/formio.js/app/sandbox
Code behind the sandbox (see initRenderer function):
https://github.com/formio/formio.js/blob/master/app/sandbox.html

Related

How to update me endpoint in Strapi?

Im working with Strapi v3.4.0 for a project. I want to allow the authenticated user to update his personal informations when hitting the following endpoint:
PUT /users/me
for now I'm just trying to console.log a message when i hit the endpoint, I have followed the step from this video: https://www.youtube.com/watch?v=ITk-pYtOCnQ but I keep getting 403 error "Forbidden". Am I doing something wrong?
I understand this update me problem in Strapi is really painful. I have also followed the tutorial on the link you put above to no avail since Strapi just updated to the new version. I tried a workaround for this solution. So basically, I tried to create an additional method on the model that shows on the api folder (Previously, I am trying to add a new method on user controller but again I got this 403 error as well). As for my approach, I created a model called User Profile and then add the custom method for updating the current user data shown below.
api/user-profile/config/routes.json
...
{
"method": "PUT",
"path": "/updateMe",
"handler": "user-profile.updateMe",
"config": {
"policies": []
}
},
{
"method": "PUT",
"path": "/user-profiles/:id",
"handler": "user-profile.update",
"config": {
"policies": []
}
}
...
and on the controller, I added the following snippets
api/user-profile/controllers/user-profile.js
'use strict';
const _ = require('lodash');
const { sanitizeEntity } = require('strapi-utils');
const sanitizeUser = user =>
sanitizeEntity(user, {
model: strapi.query('user', 'users-permissions').model,
});
const formatError = error => [
{ messages: [{ id: error.id, message: error.message, field: error.field }] },
];
module.exports = {
async updateMe(ctx) {
const { id } = ctx.state.user;
let updateData = {
...ctx.request.body,
};
const data = await strapi.plugins['users-permissions'].services.user.edit({ id }, updateData);
ctx.send(sanitizeUser(data));
},
};
After that, enable the updateMe for the public use (for now, you do not have to worry since the ctx.state.user line will check if the token is valid or not, { at least until the developer officially create this updateMe function })
That is all. You just have to pass the attributes to the body and the auth header and you are good to go. You can pretty much put the function anywhere you want
PS: Take a note that you have to put the updateMe route above the update route. Else, it will give you the same 403 error
PPS: This is just a workaround until the developer officially includes the updateMe function, which we cannot expect in short time

Mongoose - can't insert subDocuments of a Dictionary Type

I have a Mongoose schema for the document Company, that has several fields. One of these (documents_banks) is a "free" field, of dictionary type, because I don't know the names of the keys in advance.
The problem is that, when I save the document (company.save()) even if the resulting saved document has the new sub_docs, in the DB no new sub_docs are actually saved.
var Company = new Schema({
banks: [{ type: String }], // array of Strings
documents_banks: {} // free field
});
Even if documents_banks is not restricted by the Schema, it will have this structure (in my mind):
{
"bank_id1": {
"doc_type1": {
"url": { "type": "String" },
"custom_name": { "type": "String" }
},
"doc_type2": {
"url": { "type": "String" },
"custom_name": { "type": "String" }
}
},
"bank_id2": {
"doc_type1": {
"url": { "type": "String" },
"custom_name": { "type": "String" }
}
}
}
But I don't know in advance names of keys bank_id neither doc_type, so I used the Dictionary type (documents_banks:{}).
Now, this below is the function I use to save new sub_docs in documents_banks. The same logic I always use to save new sub_docs.. Anyway this time, it seems saved, but it's not.
function addBankDocument(company_id, bank_id, doc_type, url, custom_name) {
// retrieve the company document
Company.findById(company_id)
.then(function(company) {
// create empty sub_docs if needed
if (!company.documents_banks) {
company.documents_banks = {};
}
if (!company.documents_banks[bank_id]) {
company.documents_banks[bank_id] = {};
}
// add the new sub_doc
company.documents_bank[bank_id][doc_type] = {
"url": url,
"custom_name": custom_name
};
return company.save();
})
.then(function(saved_company) {
// I try to check if the new obj has been saved
console.log(saved_company.documents_bank[bank_id][doc_type]);
// and it actually prints the new obj!!
});
}
The saved_company returned by the .save() actually has the new sub_docs, but if I check the DB there is not the new sub_doc! I can save just the first one, all the others are not stored.
So, the console.log() always print the new sub_docs, but actually in the DataBase, just the first sub_doc is saved, not the others. So at the end, saved_company always has 1 sub_doc, the first one.
It seems very strange to me, since saved_company has the new sub_docs. What can be happened?
This below is a real extract from by DB, and it will contains forever just the sub_doc "doc_bank#1573807781414", others will be not present in the DB.
{
"_id": "5c6eaf8efdc21500146e289c", // company_id
"banks": [ "MPS" ],
"documents_banks": {
"5c5ac3e025acd98596021a9a": // bank_id
{
"doc_bank#1573807781414": // doc_type
{
"url": "http://...",
"custom_name": "file1"
}
}
}
}
Versions:
$ npm -v
6.4.1
$ npm show mongoose version
5.7.11
$ node -v
v8.16.0
It seems that, since mongoose doesn't know the exact model of the subdoc, it can't know when it changes. So I have to use markModified to notify changes of the "free field" (also known as dictionary or MixedType) with this:
company_doc.documents_banks["bank_id2"]["doc_type3"] = obj; // modify
company_doc.markModified('documents_banks'); // <--- notify changes
company_doc.save(); // save changes
As I understood, markModified force the model to 'update' that field during the save().

Create Entities and training phrases for values in functions for google action

I have created a trivia game using the SDK, it takes user input and then compares it to a value in my DB to see if its correct.
At the moment, I am just passing a raw input variable through my conversation, this means that it regularly fails when it mishears the user since the exact string which was picked up is rarely == to the value in the DB.
Specifically I would like it to only pick up numbers, and for example realise that it must extract '10' , from a speech input of 'my answer is 10'.
{
"actions": [
{
"description": "Default Welcome Intent",
"name": "MAIN",
"fulfillment": {
"conversationName": "welcome"
},
"intent": {
"name": "actions.intent.MAIN"
}
},
{
"description": "response",
"name": "Raw input",
"fulfillment": {
"conversationName": "rawInput"
},
"intent": {
"name": "raw.input",
"parameters": [{
"name": "number",
"type": "org.schema.type.Number"
}],
"trigger": {
"queryPatterns":[
"$org.schema.type.Number:number is the answer",
"$org.schema.type.Number:number",
"My answer is $org.schema.type.Number:number"
]
}
}
}
],
"conversations": {
"welcome": {
"name": "welcome",
"url": "https://us-central1-triviagame",
"fulfillmentApiVersion": 2
},
"rawInput": {
"name": "rawInput",
"url": "https://us-central1-triviagame",
"fulfillmentApiVersion": 2
}
}
}
app.intent('actions.intent.MAIN', (conv) => {
conv.data.answers = answersArr;
conv.data.questions = questionsArr;
conv.data.counter = answersArr.length;
var thisQuestion = conv.data.questions;
conv.ask((conv.data.answers)[0]));
});
app.intent('raw.input', (conv, input) => {
if(input == ((conv.data.answers)[0])){
conv.ask(nextQuestion());
}
app.intent('actions.intent.TEXT', (conv,input) => {
//verifying if input and db value are equal
// at the moment input is equal to 'my number is 10' (for example) instead of '10'
//therefore the string verification never works
conv.ask(nextQuestion());
});
In a previous project i used the dialogflow UI and I used this #system.entities number parameter along with creating some training phrases so it understands different speech patterns.
This input parameter I am passing through my conv , is only a raw string where I'd like it to be filtered using some sort of entity schema.
How do I create the same effect of training phrases/entities using the JSON file?
You can't do this using just the Action SDK. You need a Natural Language Processing system (such as Dialogflow) to handle this as well. The Action SDK, by itself, will do speech-to-text, and will use the actions.json configuration to help shape how to interpret the text. But it will only return the entire text from the user - it will not try to determine how it might match an Intent, nor what parameters may exist in it.
To do that, you need an NLP/NLU system. You don't need to use Dialogflow, but you will need something that does the parsing. Trying to do it with simple pattern matching or regular expressions will lead to nightmares - find a good system to do it.
If you want to stick to things you can edit yourself, Dialogflow does allow you to download its configuration files (they're just JSON), edit them, and update or replace the configuration through the UI or an API.

Storing JSON in MongoDB

I m trying to store some data in MongoDB, I am not sure of the type of data that I am being provided with as I am getting it from a formbuilder(https://github.com/kevinchappell/formBuilder) that I am using.
I am getting the data from:
document.getElementById('getJSON').addEventListener('click', function() {
var ans = formBuilder.actions.getData('json', true);
//console.log(ans);
//var ans2 = JSON.parse(ans);
alert(ans);
console.log(ans);
$.ajax({
type: "POST",
data: ans,
url: "/j",
success: function(){
console.log('success');
}
});
document.forms["myForm"].submit();
});
It reaches my back end as so:
//FETCHING THE JSON OF THE CLAUSE FORM CREATED BY THE ADMIN
router.post('/j', function(req, res, next) {
req.session.fdata = req.body; //JSON FETCHED FROM JAVASCRIPT USING AJAX, STORED IN SESSION
if(req.session.fdata==null) //CHECKING IF WE ARE RECEIVING VALUES
{
res.redirect('/admin');
}
else {
mongo.connect(url, function (err, db) {
assert.equal(null, err);
//var jfdata = JSON.parse(req.session.fdata);
db.collection('clauses').insertOne(req.session.fdata, function (err, result) {
console.log('New Clause Added');
console.log(req.session.fdata);
db.close();
});
});
res.redirect('/admin');
}
});
I insert it into the DB and it looks fine in the DB but on retrieval I cant seem to access the inner portions of the data. Is my data in the wrong format? Is it JSON or a JS object?
it looks like so in the DB:(the db is empty before insertion)enter image description here
This is what the console prints
[ { _id: 596de520ef77eb2614cd1e47,
'[\n\t{\n\t\t"type": "number",\n\t\t"label": "Number",\n\t\t"description":
"total number",\n\t\t"placeholder": "0",\n\t\t"className": "form-
control",\n\t\t"name": "number-1500374279764"\n\t}\n]': '' },
{ _id: 596de520ef77eb2614cd1e48 } ]
The data you are trying to save does not seem right to me.
What you are getting is a string of the JSON object.
You have to use JSON.parse to convert it to a proper JSON object.
JSON.parse('[\n\t{\n\t\t"type": "number",\n\t\t"label":"Number",\n\t\t"description": "total number",\n\t\t"placeholder": "0",\n\t\t"className": "form-control",\n\t\t"name": "number-1500374279764"\n\t}\n]')
After that, you can form the data and insert in DB.
var query = {
array : [{"type": "number",
"label": "Number",
"description": "total number",
"placeholder": "0",
"className": "form-control",
"name": "number - 1500374279764"}]
}
db.collection('clauses').insertOne(query, function (err, result)
{
db.close();
});
Let me know if it helps!

Existing ForerunnerDB database cleared after new ForerunnerDB() command

Cannot get ForerunnerDB to load existing data. Upon browser refresh, entire IndexedDB database disappears from Chrome resources after executing new ForeRunnerDB() command.
var fdb = new ForerunnerDB();
// Existing database disappears from Chrome resources here
var db = fdb.db('VRC');
db.collection('videos').load();
var videoCollection = db.collection('videos');
if (!videoCollection.count()) {
videoCollection.setData([
{
"_id": 1,
"name": "Joe"
},
{
"_id": 2,
"name": "Susan"
}]);
// Yeah, I know this is redundant...
videoCollection.save();
db.save();
ForerunnerDB.save();
}
Problem was solved by passing a function to Collection.load():
videoCollection.load(function() {
// Do something with data here
});