Create Google Map Widget in SurveyJs - javascript

I'm a newcomer to SurveyJS. I want to add Google Map as a widget to SurveyJS.
I did some steps and the map was added correctly in the Survey Designer section, but it does not load my widget in the Test Survey section.
I have uploaded the codes and images below
please guide me
Thanks
angular: ^7.3.9,
survey-analytics: ^1.7.26,
survey-angular: ^1.8.70,
survey-creator: ^1.8.70,
survey-knockout: ^1.8.70 ,
survey-pdf: ^1.8.70,
surveyjs-widgets: ^1.8.70,
fileName: mapWidget.ts
import { Loader } from "#googlemaps/js-api-loader";
export function init(Survey: any) {
var widget = {
name: "googlemap",
title: "google map survey",
iconName: "my-custom-icon",
init() {},
widgetIsLoaded: function () {
return true;
},
isFit: function (question: any) {
let type = question.getType();
return type === "googlemap";
},
activatedByChanged: function (activatedBy) {
Survey.JsonObject.metaData.addClass("googlemap", [], null, "text");
Survey.JsonObject.metaData.addProperties("googlemap", [
{ name: "lat", default: 29.635703 },
{ name: "lng", default: 52.521924 },
]);
createProperties(Survey);
},
isDefaultRender: false,
htmlTemplate:
"<div class='custom-tessting-input' id='google-map-design'></div>",
afterRender: function (question: any, element: any) {
debugger;
var findDiv = document.getElementById("google-map-design");
findDiv.style.height = "500px";
findDiv.style.width = "100%";
let loader = new Loader({
apiKey: "xxxxxxxxxxx",
});
loader
.load()
.then((google) => {
new google.maps.Map(document.getElementById("google-map-design"), {
center: { lat: question.lat, lng: question.lng },
zoom: 6,
});
})
.catch((err) => {});
},
};
Survey.CustomWidgetCollection.Instance.add(widget, "customtype");
}
function createProperties(Survey) {
var props = createGeneralProperties(Survey);
return props;
}
function createGeneralProperties(Survey) {
return Survey.Serializer.addProperties("googlemap", [
{
name: "latitude:textbox",
category: "general",
default: "29.635703",
},
{
name: "longitude:textbox",
category: "general",
default: "52.521924",
},
]);
}
fileName: survey.creator.component.ts
//...
import { init as initGoogleMapWidget } from "./mapWidget";
...
initGoogleMapWidget(SurveyKo);
//...
fileName: survey.component.ts
//...
import { init as initGoogleMapWidget } from "./mapWidget";
...
initGoogleMapWidget(SurveyKo);
//...

Try this one in survey.component.ts:
//...
import { init as initGoogleMapWidget } from "./mapWidget";
...
initGoogleMapWidget(Survey);
//...
When we want to create a survey, we pass SurveyKo. But when we want to see the created survey, we pass Survey which is the survey instance.

Related

how to pass value from method in angular to property

Hello I'm trying to pass value from a method to a property
here's my code
I want to pass sub_id_1 to the options under subscription_id
I'm trying for 3 days any help, please
this is a razor integration I'm fetching the response from python and get it back in angular but I fell that I'm locked at buy() method
public buy() {
return this.http.get("http://127.0.0.1:5000/razor_sub",{
}).subscribe(
(res)=>{
var rrre = res.json();
var sub_id_1 = rrre.id;
if (sub_id_1) {
console.log(sub_id_1);
const type = sub_id_1;
this.sub_response_id(sub_id_1)
}
});
}
/**
* sub_response_id
*/
public sub_response_id(sub_id_1) {
this.initPay(sub_id_1)
}
public options: any = {
key: 'rzp_test_******',
subscription_id: this.sub_response_id(sub_id_1),
name: "Acme Corp.",
description: "Monthly Test Plan",
image: "#",
handler: function(response) {
//alert(response.razorpay_payment_id),
//alert(response.razorpay_subscription_id),
//alert(response.razorpay_signature);
},
prefill: {
name: "Tamer Jarrar",
email: "tamerjrrar#example.com",
contact: "+919876543210"
},
notes: {
note_key_1: "Tea. Earl Grey. Hot",
note_key_2: "Make it so."
},
theme: {
color: "#F37254"
}
};
initPay(sub_id_1): void {
this.rzp = new this.winRef.nativeWindow['Razorpay'](this.options);
this.rzp.open();
}
paymentHandler(res: any) {
this.zone.run(() => {
});
}
buy() {
return this.http
.get("http://127.0.0.1:5000/razor_sub", {} )
.subscribe(res => {
const { id } = res;
if (id) {
const options = getOptions(id);
this.initPay(options);
}
}
);
}
getOptions(subscription_id) {
return {
key: 'rzp_test_******',
subscription_id,
name: "Acme Corp.",
...
}
};
initPay(options) {
this.rzp = new this.winRef.nativeWindow['Razorpay'](options);
this.rzp.open();
}
Is that what you need?
i ignore some not-related part of your code, just show the key part of your problem.
you see multiple problems exist in your code to transform some variance to subscription_id.
please reference this:
public buy() {
return setTimeout(() => {
debugger;
var sub_id_1 = 3333;
if (sub_id_1) {
console.log("sub_id_1 is", sub_id_1);
this.options.subscription_id = this.sub_response_id(sub_id_1);
console.log("subscription_id", this.options.subscription_id);
}
}, 1000);
}
/**
* sub_response_id
*/
public sub_response_id(sub_id_1) {
// this.initPay(sub_id_1);
return sub_id_1 + 3333;
}
public options: any = {
key: "rzp_test_******",
subscription_id: 111,
name: "Acme Corp.",
description: "Monthly Test Plan",
image: "#",
handler: function (response) {
//alert(response.razorpay_payment_id),
//alert(response.razorpay_subscription_id),
//alert(response.razorpay_signature);
},
prefill: {
name: "Tamer Jarrar",
email: "tamerjrrar#example.com",
contact: "+919876543210"
},
notes: {
note_key_1: "Tea. Earl Grey. Hot",
note_key_2: "Make it so."
},
theme: {
color: "#F37254"
}
};

Tiptap extension for images and editable captions

enter image description here
I want to implement image and editable caption with tiptap extension
https://discuss.prosemirror.net/t/figure-and-editable-caption/462
There was a very good example with ProseMirror, but is it difficult to achieve with tiptap?
Please tell me what code you should write if possible.
I attach the code that I wrote below.
The image and caption have been successfully added, but the caption cannot be edited yet.
// ./CustomImage.ts
// #ts-ignore
import { Node, Plugin } from 'tiptap'
// #ts-ignore
import { nodeInputRule } from 'tiptap-commands'
const IMAGE_INPUT_REGEX = /!\[(.+|:?)\]\((\S+)(?:(?:\s+)["'](\S+)["'])?\)/
export default class CustomImage extends Node {
get name () {
return 'customImage'
}
get schema () {
return {
attrs: {
src: {
default: null
},
alt: {
default: null
},
title: {
default: null
},
caption: {
default: null
}
},
group: 'block',
selectable: false,
draggable: true,
parseDOM: [
{
tag: 'figure'
},
[
{
tag: 'img[src]',
getAttrs: (dom: any) => ({
src: dom.getAttribute('src'),
title: dom.getAttribute('title'),
alt: dom.getAttribute('alt')
})
},
{
tag: 'figcaption'
}
]
],
toDOM: (node: any) => [
'figure',
[
'img',
{
src: node.attrs.src,
title: node.attrs.title,
alt: node.attrs.alt
}
],
[
'figcaption',
{
contenteditable: 'true'
},
node.attrs.caption
]
]
}
}
commands ({ type }: any) {
return (attrs: any) => (state: any, dispatch: any) => {
const { selection } = state
const position = selection.$cursor ? selection.$cursor.pos : selection.$to.pos
const node = type.create(attrs)
const transaction = state.tr.insert(position, node)
dispatch(transaction)
}
}
inputRules ({ type }: any) {
return [
nodeInputRule(IMAGE_INPUT_REGEX, type, (match: any) => {
const [, alt, src, title] = match
return {
src,
alt,
title
}
})
]
}
get plugins () {
return [
new Plugin({
props: {
handleDOMEvents: {
drop (view: any, event: any) {
const hasFiles = event.dataTransfer &&
event.dataTransfer.files &&
event.dataTransfer.files.length
if (!hasFiles) {
return
}
const images = Array
.from(event.dataTransfer.files)
.filter((file: any) => (/image/i).test(file.type))
if (images.length === 0) {
return
}
event.preventDefault()
const { schema } = view.state
const coordinates = view.posAtCoords({ left: event.clientX, top: event.clientY })
images.forEach((image: any) => {
const reader = new FileReader()
reader.onload = (readerEvent: any) => {
const node = schema.nodes.image.create({
src: readerEvent.target.result
})
const transaction = view.state.tr.insert(coordinates.pos, node)
view.dispatch(transaction)
}
reader.readAsDataURL(image)
})
}
}
}
})
]
}
}
You're missing a "hole" in the figure caption to make it editable. See https://prosemirror.net/docs/ref/#model.NodeSpec.toDOM. I implemented one of the solutions mentioned in the ProseMirror thread mentioned; however, the cursor can still enter text in between image and figurecaption. I would recommend using the last example with 3 schemas instead.
get schema() {
return {
content: "inline*",
attrs: {src: {default: ""}, title: {default: ""}},
group: 'block',
draggable: true,
isolating: true,
parseDOM: [{
tag: "figure",
contentElement: "figcaption",
getAttrs(dom) {
let img = dom.querySelector("img")
console.log(img, img.getAttribute('src'), img.getAttribute('alt'));
return {src: img.getAttribute('src'), title: img.getAttribute('alt')}
}
}],
toDOM: node => ["figure", ["img", node.attrs], ["figurecaption", 0]],
}
}

Zapier JS conditional statement

I'm noob at JS, trying to write an APP for zapier. I have a test auth function that I can't get to fail when bad info is sent in.
Here is the test function:
require('should');
const zapier = require('zapier-platform-core');
const App = require('../../index');
const appTester = zapier.createAppTester(App);
describe('Triggers - Get Groups', () => {
zapier.tools.env.inject();
it('should get an array', done => {
const bundle = {
authData: { api_key: process.env.API_KEY },
inputData: {}
};
appTester(App.triggers['getgroup'].operation.perform, bundle)
.then(results => {
results.includes('id');
done();
})
.catch(results);
});
});
If successfull, a sample return should look like this:
{"id":1815,"name":"New Contacts","count":2}
A failure looks like this:
{"RESPONSE":"FAIL","REASON":"Invalid API key"}
Here is the getgroup function:
// Trigger stub created by 'zapier convert'. This is just a stub - you will need to edit!
const { replaceVars } = require('../utils');
const getList = (z, bundle) => {
let url = 'https://path.to/apisite?action=getGroups&apiKey={{api_key}}';
url = replaceVars(url, bundle);
const responsePromise = z.request({ url });
return responsePromise.then(response => {
response.throwForStatus();
return z.JSON.parse(response.content);
});
};
module.exports = {
key: 'getgroup',
noun: 'Getgroup',
display: {
label: 'Get Groups',
description: 'Triggers when loaded to pull groups.',
hidden: true,
important: false
},
operation: {
inputFields: [
{
key: 'group',
label: 'Groupget',
type: 'string',
required: false
}
],
outputFields: [
{
key: 'count',
type: 'string'
},
{
key: 'id',
type: 'string',
label: 'groupid'
},
{
key: 'name',
type: 'string',
label: 'groupname'
}
],
perform: getList,
sample: { count: 243, id: 27806, name: 'New Contacts' }
}
};
When I test auth on Zapier's website, I'd like auth to fail, and return the "REASON"
How do I do this?

How to make a custom route for users? And how to add hooks to it?

I'm trying to add a route /me to get user authenticated information. This is what I have at my files.
I've tried adding a route /me at users.services file, but I'm getting this error: "error: MethodNotAllowed: Method find is not supported by this endpoint."
I want to get response with a user object (based on token) to a GET method to route '/me'.
users.service.js
// Initializes the `users` service on path `/users`
const createService = require('feathers-sequelize');
const createModel = require('../../models/users.model');
const hooks = require('./users.hooks');
module.exports = function (app) {
const Model = createModel(app);
const paginate = app.get('paginate');
const options = {
name: 'users',
Model,
paginate
};
// Initialize our service with any options it requires
app.use('/users', createService(options));
app.use('/me', {
get(id, params) {
return Promise.resolve([
{
id: 1,
text: 'Message 1'
}
])
}
})
// Get our initialized service so that we can register hooks and filters
const service = app.service('users');
service.hooks(hooks);
};
users.hooks.js
const { authenticate } = require('#feathersjs/authentication').hooks;
const {
hashPassword, protect
} = require('#feathersjs/authentication-local').hooks;
module.exports = {
before: {
all: [ ],
find: [ authenticate('jwt') ],
get: [],
create: [ hashPassword() ],
update: [ hashPassword() ],
patch: [ hashPassword() ],
remove: []
},
after: {
all: [
// Make sure the password field is never sent to the client
// Always must be the last hook
protect('password')
],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
},
error: {
all: [],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
}
};
users.model.js
// See http://docs.sequelizejs.com/en/latest/docs/models-definition/
// for more of what you can do here.
const Sequelize = require('sequelize');
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get('sequelizeClient');
const users = sequelizeClient.define('users', {
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: false
},
}, {
hooks: {
beforeCount(options) {
options.raw = true;
}
}
});
users.associate = function (models) { // eslint-disable-line no-unused-vars
// Define associations here
// See http://docs.sequelizejs.com/en/latest/docs/associations/
};
return users;
};
What you did through
app.use('/me', {
get(id, params) {
return Promise.resolve([
{
id: 1,
text: 'Message 1'
}
])
}
})
Was implement routes for /me/:id. The find method is what runs for the base route of /me.
I don't think a separate service is really necessary though. An easier solution would be to use a before all hook that changes the id if you are accessing /users/me:
module.exports = function() {
return async context => {
if(context.id === 'me') {
context.id = context.params.user._id;
}
}
}

GraphQL Validation Error on mutation

I am trying to set up a mutation with modified code from the Relay Todo example.
When I try to compile I get the following error:
-- GraphQL Validation Error -- AddCampaignMutation --
File: /Users/me/docker/relay/examples/todo/js/mutations/AddCampaignMutation.js
Error: Cannot query field "addCampaign" on type "Mutation".
Source:
>
> mutation AddCampaignMutation {addCampaign}
> ^^^
-- GraphQL Validation Error -- AddCampaignMutation --
File: /Users/me/docker/relay/examples/todo/js/mutations/AddCampaignMutation.js
Error: Unknown type "AddCampaignPayload". Did you mean "AddTodoPayload" or "RenameTodoPayload"?
Source:
>
> fragment AddCampaignMutationRelayQL on AddCampaignPayload #relay(pattern: true) {
> ^^
I have duplicated the Todo code so I don't know why the Todo mutation is working correctly but my new Campaign test isn't.
This is my database.js file, I have removed the Todo related items to make the document easier to read:
export class Campaign {}
export class User {}
// Mock authenticated ID
const VIEWER_ID = 'me';
// Mock user data
const viewer = new User();
viewer.id = VIEWER_ID;
const usersById = {
[VIEWER_ID]: viewer,
};
// Mock campaign data
const campaignsById = {};
const campaignIdsByUser = {
[VIEWER_ID]: [],
};
let nextCampaignId = 0;
addCampaign('Campaign1');
addCampaign('Campaign2');
addCampaign('Campaign3');
addCampaign('Campaign4');
export function addCampaign(text) {
const campaign = new Campaign();
//campaign.complete = !!complete;
campaign.id = `${nextCampaignId++}`;
campaign.text = text;
campaignsById[campaign.id] = campaign;
campaignIdsByUser[VIEWER_ID].push(campaign.id);
return campaign.id;
}
export function getCampaign(id) {
return campaignsById[id];
}
export function getCampaigns(status = 'any') {
const campaigns = campaignIdsByUser[VIEWER_ID].map(id => campaignsById[id]);
if (status === 'any') {
return campaigns;
}
return campaigns.filter(campaign => campaign.complete === (status === 'completed'));
}
This is my schema.js file, again I have removed the Todo related items to make the document easier to read:
import {
GraphQLBoolean,
GraphQLID,
GraphQLInt,
GraphQLList,
GraphQLNonNull,
GraphQLObjectType,
GraphQLSchema,
GraphQLString,
} from 'graphql';
import {
connectionArgs,
connectionDefinitions,
connectionFromArray,
cursorForObjectInConnection,
fromGlobalId,
globalIdField,
mutationWithClientMutationId,
nodeDefinitions,
toGlobalId,
} from 'graphql-relay';
import {
Campaign,
addCampaign,
getCampaign,
getCampaigns,
User,
getViewer,
} from './database';
const {nodeInterface, nodeField} = nodeDefinitions(
(globalId) => {
const {type, id} = fromGlobalId(globalId);
if (type === 'User') {
return getUser(id);
} else if (type === 'Campaign') {
return getCampaign(id);
}
return null;
},
(obj) => {
if (obj instanceof User) {
return GraphQLUser;
} else if (obj instanceof Campaign) {
return GraphQLCampaign;
}
return null;
}
);
/**
* Define your own connection types here
*/
const GraphQLAddCampaignMutation = mutationWithClientMutationId({
name: 'AddCampaign',
inputFields: {
text: { type: new GraphQLNonNull(GraphQLString) },
},
outputFields: {
campaignEdge: {
type: GraphQLCampaignEdge,
resolve: ({localCampaignId}) => {
const campaign = getCampaign(localCampaignId);
return {
cursor: cursorForObjectInConnection(getCampaigns(), campaign),
node: campaign,
};
},
},
viewer: {
type: GraphQLUser,
resolve: () => getViewer(),
},
},
mutateAndGetPayload: ({text}) => {
const localCampaignId = addCampaign(text);
return {localCampaignId};
},
});
const GraphQLCampaign = new GraphQLObjectType({
name: 'Campaign',
description: 'Campaign integrated in our starter kit',
fields: () => ({
id: globalIdField('Campaign'),
text: {
type: GraphQLString,
description: 'Name of the campaign',
resolve: (obj) => obj.text,
}
}),
interfaces: [nodeInterface]
});
const {
connectionType: CampaignsConnection,
edgeType: GraphQLCampaignEdge,
} = connectionDefinitions({
name: 'Campaign',
nodeType: GraphQLCampaign,
});
const GraphQLUser = new GraphQLObjectType({
name: 'User',
fields: {
id: globalIdField('User'),
campaigns: {
type: CampaignsConnection,
args: {
...connectionArgs,
},
resolve: (obj, {...args}) =>
connectionFromArray(getCampaigns(), args),
},
totalCount: {
type: GraphQLInt,
resolve: () => getTodos().length,
},
completedCount: {
type: GraphQLInt,
resolve: () => getTodos('completed').length,
},
},
interfaces: [nodeInterface],
});
const Root = new GraphQLObjectType({
name: 'Root',
fields: {
viewer: {
type: GraphQLUser,
resolve: () => getViewer(),
},
node: nodeField,
},
});
This is my AddCampaignMutation.js file:
import Relay from 'react-relay';
export default class AddCampaignMutation extends Relay.Mutation {
static fragments = {
viewer: () => Relay.QL`
fragment on User {
id,
totalCount,
}
`,
};
getMutation() {
console.log('getMutation');
return Relay.QL`mutation{addCampaign}`;
}
getFatQuery() {
console.log('getFatQuery');
return Relay.QL`
fragment on AddCampaignPayload #relay(pattern: true) {
campaignEdge,
viewer {
campaigns,
},
}
`;
}
getConfigs() {
console.log('getConfigs');
return [{
type: 'RANGE_ADD',
parentName: 'viewer',
parentID: this.props.viewer.id,
connectionName: 'campaigns',
edgeName: 'campaignEdge',
rangeBehaviors: ({orderby}) => {
if (orderby === 'newest') {
return 'prepend';
} else {
return 'append';
}
},
//rangeBehaviors: ({status}) => {
// if (status === 'completed') {
// return 'ignore';
// } else {
// return 'append';
// }
//},
}];
}
getVariables() {
console.log('getVariables');
return {
text: this.props.text,
};
}
getOptimisticResponse() {
console.log('getOptimisticResponse');
return {
// FIXME: totalCount gets updated optimistically, but this edge does not
// get added until the server responds
campaignEdge: {
node: {
text: this.props.text,
},
},
viewer: {
id: this.props.viewer.id,
totalCount: this.props.viewer.totalCount + 1,
},
};
}
}
And finally this is the app file that contains my text input and the call to AddCampaignMutation:
import AddTodoMutation from '../mutations/AddTodoMutation';
import AddCampaignMutation from '../mutations/AddCampaignMutation';
import TodoListFooter from './TodoListFooter';
import TodoTextInput from './TodoTextInput';
import React from 'react';
import Relay from 'react-relay';
class TodoApp extends React.Component {
_handleTextInputSave = (text) => {
debugger;
this.props.relay.commitUpdate(
new AddTodoMutation({text, viewer: this.props.viewer})
);
};
_campaignHandleTextInputSave = (text) => {
debugger;
this.props.relay.commitUpdate(
new AddCampaignMutation({text, viewer: this.props.viewer})
);
};
render() {
const hasTodos = this.props.viewer.totalCount > 0;
return (
<div>
<section className="todoapp">
<header className="header">
<TodoTextInput
autoFocus={true}
className="new-campaign"
onSave={this._campaignHandleTextInputSave}
placeholder="Campaign name"
/>
<h1>
todos
</h1>
<TodoTextInput
autoFocus={true}
className="new-todo"
onSave={this._handleTextInputSave}
placeholder="What needs to be done?"
/>
</header>
{this.props.children}
{hasTodos &&
<TodoListFooter
todos={this.props.viewer.todos}
viewer={this.props.viewer}
/>
}
</section>
</div>
);
}
}
export default Relay.createContainer(TodoApp, {
fragments: {
viewer: () => Relay.QL`
fragment on User {
totalCount,
${AddTodoMutation.getFragment('viewer')},
${AddCampaignMutation.getFragment('viewer')},
${TodoListFooter.getFragment('viewer')},
}
`,
},
});
Well I feel a bit silly but I found out what the problem was. I didn't realise that my schema.json file was not updating!
If anyone has a similar problem make sure that the schema.json file is up to date by running the following command to rebuild it:
npm run-script update-schema

Categories

Resources