convert vue ast back to template - vue.js

I'm using vue-template-compiler to transform a text in the vue template to an expression
I have this vueJs file
<template>
<p>hi</p>
</template>
I'm trying to change the text with expression like this
<p>{{fun('hi')}}</p>
my code
const compiled = compiler.compile(
data,
{
modules: [
{
transformNode(data) {
const children = data.children.map((child) => {
if (child.type === 3 && child.text.trim()) {
return ({
type: 2,
expression: "_s(fun('hi'))",
tokens: [
{
'#binding': "fun('hi')"
}
],
text: "{{fun('hi)}}"
})
}
return child;
});
return { ...data, children };
},
},
],
},
{
whitespace: "condense",
}
);
it maps over the texts and replace it with the expression.
and it returns the final ast.
but I need to convert it back to string
like that:
<p>{{fun('hi')}}</p>
I need to convert the final ast back to the template

Related

Ramda: filtering an array against an array of items

I have a working function to filter the following array:
const arrayOne = [
{
node: {
caseStudyFields: {
filterTags: [
"Temperature control"
]
}
}
},
{
node: {
caseStudyFields: {
filterTags: null
}
}
},
{
node: {
caseStudyFields: {
filterTags: [
"Specialist manufacturing",
"Pharmaceuticals"
]
}
}
},
]
const arrayTwo = [
'Pharmaceuticals',
'Specialist manufacturing',
'Temperature control'
]
const fn = n => n.node.caseStudyFields.filterTags &&
n.node.caseStudyFields.filterTags.some(r => arrayTwo.includes(r))
return arrayOne.filter(fn)
This code works fine, but I wanted to convert it to Ramda (for fun). I've got so far in finding the path but I've become confused with the some and includes (any in Ramda?)
const filter = R.filter(
R.pipe(
R.path(['node', 'caseStudyFields', 'filterTags']),
)
);
return filter(arrayOne)
Use R.pathOr to get the value at the path, and return and empty array if it's null. This will prevent filter from erroring when encountering the null.
Use R.any (Ramda's equivalent to Array.some()) with R.includes, curried with the array of tags, to find matching items:
const { curry, filter, pipe, pathOr, any, includes, __ } = R
const filterByTags = curry((tags, arr) =>
filter(pipe(
pathOr([], ['node', 'caseStudyFields', 'filterTags']),
any(includes(__, tags))
))
(arr))
const arrayOne = [{"node":{"caseStudyFields":{"filterTags":["Temperature control"]}}},{"node":{"caseStudyFields":{"filterTags":null}}},{"node":{"caseStudyFields":{"filterTags":["Specialist manufacturing","Pharmaceuticals"]}}}]
const arrayTwo = ["Pharmaceuticals","Specialist manufacturing","Temperature control"]
const result = filterByTags(arrayTwo, arrayOne)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>

Strapi graphql mutation Syntax Error: Unterminated string

I always get Syntax Error: Unterminated string when I try to update my database using javascript strapi sdk. this.chapter.content is a html string generated by ckeditor. How can I escape this string to update my database using graphql?
async updateChapter() {
const q = `
mutation {
updateChapter(input: {
where: {
id: "${this.$route.params.chapterId}"
},
data: {
content: "${this.chapter.content.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/(?:\r\n|\r|\n)/g, '\n')}"
title: "${this.chapter.title}"
}
}) {
chapter{
title
id
content
}
}
}
`;
const res = await strapi.request("post", "/graphql", {
data: {
query: q
}
});
this.chapter = res.data.chapter;
}
Technically you could use block string notation to get around this issue. However, you really should supply dynamic input values using variables instead of string interpolation. This way you can easily provide any of sort of values (strings, numbers, objects, etc.) and GraphQL will parse them accordingly -- including strings with line breaks.
const query = `
mutation MyMutation ($chapterId: ID!, $content: String!, $title: String!) {
updateChapter(input: {
where: {
id: $chapterId
},
data: {
content: $content
title: $title
}
}) {
chapter{
title
id
content
}
}
}
`
const variables = {
chapterId: '...',
content: '...',
title: '...',
}
const res = await strapi.request("post", "/graphql", {
data: {
query,
variables,
},
})
Note that $chapterId may need to be of the type String! instead if that's what's called for in the schema. Since variables can also be input object types, instead of providing 3 different variables, you could also provide a single variable to be passed to the input argument instead:
const query = `
mutation MyMutation ($input: SomeInputObjectTypeHere!) {
updateChapter(input: $input) {
chapter{
title
id
content
}
}
}
`
const variables = {
input: {
where: {
id: '...',
},
data: {
content: '...',
title: '...',
},
},
}
Again, just replace SomeInputObjectTypeHere with the appropriate type in your schema.
Another solution maybe help
Code with issue: For example mainReason and actionTaken fields are text inputs and data contains some white spaces. This action give error: Unterminated string
mutation { updateApplicationForm(input:{ where:{id:"${ticketData.id}"}
data:{
mainReason: "${ticketData.mainReason}"
actionTaken: "${ticketData.actionTaken}"
appStatus: ${ticketData.appStatus}
action: "${ticketData.action}"
}
Fix this problem with JSON.stringify method
mutation { updateApplicationForm(input:{ where:{id:"${ticketData.id}"}
data:{
mainReason:${JSON.stringify(ticketData.mainReason)}
actionTaken:${JSON.stringify(ticketData.actionTaken)}
appStatus: ${ticketData.appStatus}
action: "${ticketData.action}"
}

How to dynamically render strings in Vue?

I am pulling an array on images from Netlify CMS and passing that to vue-picture-swipe component, but the acutal images don't render, even though the path is correct etc.
Not sure what I am doing wrong?
Template
vue-picture-swipe(:items="items")
Script
<script>
export default {
data: function() {
return {
items: []
};
},
created: function () {
this.imageList()
},
methods: {
imageList: function () {
const files = require.context('~/content/gallery/images/', false, /\.md$/);
let images = files.keys().map(key => ({
...files(key)
}));
let items = images.map(function(value) {
return {
'src': value.attributes.imgSrc,
'thumbnail': value.attributes.imgSrc,
'alt': value.attributes.imgDesc
}
});
return this.items = items
}
}
};
</script>
Rendered HTML
<img src="/assets/uploads/image.jpg" alt="Test Image description" itemprop="thumbnail">
According to your output, if value.attributes.imgSrc renders a relative path like src="/assets/uploads/image.jpg", try to require this path.
I'm assuming your "assets" and "components" folders are directly under "src":
let items = images.map(function(value) {
return {
'src': require('..' + value.attributes.imgSrc), // or require('#' + value.attributes.imgSrc)
'thumbnail': require('..' + value.attributes.imgSrc),
'alt': value.attributes.imgDesc
}
})
Note that vue-picture-swipe items props need w and h attributes for each item.

sending vuejs data post request as array of ints instead of strings

I have 2 input boxes for weights and values, and I can then click a button to automatically create more. This part is working fine.
The problem now is that the server expects a JSON formdata request containing array of ints, rather than strings.
This is how the postdata should look like:
{"stuff": {"weights": [2, 5, 3], "values": [654, 23, 3]}}
This is what it ends up looking like:
{"stuff": {"weights": ["2", "5", "3"], "values": ["654", "23", "3"]}}
I have tried to search how to set data array type to int, how to save v-model as int, etc.
I believe this is all the relevant code:
<template>
..
<div v-for="(weight, index) in weights">
<div>
<label for="w">weight:</label>
<input v-model="weights[index]">
<label for="v">value:</label>
<input v-model="values[index]">
</div>
</div>
..
</template>
<script>
export default {
data () {
return {
weights: [],
values: []
}
},
methods: {
solve: function () {
var formData = {
stuff: {
weights: this.weights,
values: this.values
}
}
axios.post('http://localhost:8000/my/api/url', formData).then(response => {
console.log(response)
}).catch(e => {
console.log(e)
})
},
...
</script>
You can use parseInt to convert them:
export default {
data () {
return {
weights: [],
values: []
}
},
computed: {
formData() {
return {
stuff: {
weights: this.weights.map((x) => parseInt(x, 10),
values: this.values.map((x) => parseInt(x, 10)
}
}
}
},
methods: {
solve: function () {
axios.post('http://localhost:8000/my/api/url', this.formData).then(response => {
console.log(response)
}).catch(e => {
console.log(e)
})
},
...
I used a computed variable to make the API call code cleaner, but it would work the same in there. The extra argument 10 is important with parseInt, it ensures the integer is base 10 which could otherwise cause odd behavior.
You can use the .number modifier:
<input v-model.number="weights[index]">
But this allows non-integer numbers and strings (it can be an empty string if the input is empty, for example). For this reason, you should explicitly convert the weights to integers at the API call:
// You should validate the data first
var formData = {
stuff: {
weights: this.weights.map(x => parseInt(x, 10)), // Convert to integer
values: this.values.map(x => parseInt(x, 10))
}
}

Vue.js - Element UI - HTML message in MessageBox

I'm using vue-js 2.3 and element-ui. This question is more specific to the MessageBox component for which you can find the documentation here
Problem
I'd like to be able to enter html message in the MessageBox
More specifically I would like to display the data contained in dataForMessage by using a v-for loop.
Apparently, we can insert vnode in the message but I have no idea where to find some information about the syntax.
https://jsfiddle.net/7ugahcfz/
var Main = {
data:function () {
return {
dataForMessage: [
{
name:'Paul',
gender:'Male',
},
{
name:'Anna',
gender:'Female',
},
],
}
},
methods: {
open() {
const h = this.$createElement;
this.$msgbox({
title: 'Message',
message: h('p', null, [
h('span', null, 'Message can be '),
h('i', { style: 'color: teal' }, 'VNode '),
h('span', null, 'but I would like to see the data from '),
h('i', { style: 'color: teal' }, 'dataForMessage'),
])
}).then(action => {
});
},
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
I think this is what you want.
methods: {
open() {
const h = this.$createElement;
let people = this.dataForMessage.map(p => h('li', `${p.name} ${p.gender}`))
const message = h('div', null, [
h('h1', "Model wished"),
h('div', "The data contained in dataForMessage are:"),
h('ul', people)
])
this.$msgbox({
title: 'Message',
message
}).then(action => {
});
},
}
Example.
You can also use html directly and convert to vnodes by using domProps:
const html = '<div><h1>Model wished</h1><div>The data contained in dataForMessage are:</div><ul><li>Paul Male</li><li>Anna Female</li></ul></div>'
const message = h("div", {domProps:{innerHTML: html}})
(The above is simplified without the loop. Just to get the idea)
Fiddle