Vue.js - Element UI - HTML message in MessageBox - vue.js

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

Related

Apollo-client: How to add cache fragment in different Query?

when I create feed in Screen A,
I add and in order to apply this change to screen directly I change cache like below.
in this Screen A, I use seeAllFeeds query.
So I add this added feed to seeAllFeeds.
const updateUploadPhoto = (cache, result) => {
const {
data: { createFeed },
} = result;
if (createFeed.id) {
cache.modify({
id: "ROOT_QUERY",
fields: {
seeAllFeeds(prev) {
return [createFeed, ...prev];
},
},
});
}
}
So it works well.
But problem is I use seeCertainUserFeedpoem query in Screen B.
And here, I also need to add this added feed info.
However this screen is not applied unless I refresh the screen.
(Due to flatlist, I can't refresh because if so, scroll goes to top.)
So I add this cache.modify once again below.
I also match the data with seeCertainUserFeedpoem manually and update.
const updateUploadPhoto = (cache, result) => {
const {
data: { createFeed },
} = result;
const FeedpomeId = `Feedpoem:${createFeed.id}`;
const FeedpoemFragment = {
caption: createFeed.caption,
commentNumber: createFeed.commentNumber,
createdAt: createFeed.createdAt,
id: createFeed.id,
isLiked: createFeed.isLiked,
isMine: createFeed.isMine,
likeNumber: createFeed.likeNumber,
photos: createFeed.photos,
poemCaption: null,
poemCommentNumber: 0,
poemLikeNumber: 0,
poemTitle: null,
updatedAt: createFeed.updatedAt,
};
if (createFeed.id) {
cache.modify({
id: "ROOT_QUERY",
fields: {
seeAllFeeds(prev) {
return [createFeed, ...prev];
},
},
});
cache.modify({
id: FeedpomeId,
data: FeedpoemFragment,
});
navigation.navigate("Tabs", { screen: "일상" });
}
};
So I also try this way, not cache.modify but client.writeFragment.
const updateUploadPhoto = (cache, result) => {
const {
data: { createFeed },
} = result;
const FeedpomeId = `Feedpoem:${createFeed.id}`;
const FeedpoemFragment = {
caption: createFeed.caption,
commentNumber: createFeed.commentNumber,
createdAt: createFeed.createdAt,
id: createFeed.id,
isLiked: createFeed.isLiked,
isMine: createFeed.isMine,
likeNumber: createFeed.likeNumber,
photos: createFeed.photos,
poemCaption: null,
poemCommentNumber: 0,
poemLikeNumber: 0,
poemTitle: null,
updatedAt: createFeed.updatedAt,
};
if (createFeed.id) {
cache.modify({
id: "ROOT_QUERY",
fields: {
seeAllFeeds(prev) {
return [createFeed, ...prev];
},
},
});
client.writeFragment({
id: FeedpomeId,
data: FeedpoemFragment,
});
navigation.navigate("Tabs", { screen: "일상" });
}
};
But both dont' work.
And 2nd way throws me this error.
LogBox.js:173 Possible Unhandled Promise Rejection (id: 0): Error:
Cannot read properties of undefined (reading 'definitions') Error:
Cannot read properties of undefined (reading 'definitions')
what is the problem here?
I can edit / delete with cache.
Because I understand that first find the exact cache by id.
However creating is hard.
I want to share my cache as well.
But this is too long.
chat is also welcome, please help me.

Zapier Dynamic Custom Fields

I am trying to offer custom fields from a platform as input fields I have done this in the past with another platform and with Zapiers older UI. It does not seem to be that simple now.
const options = {
url: 'https://edapi.campaigner.com/v1/Database',
method: 'GET',
headers: {
'X-API-KEY': bundle.authData.ApiKey
},
params: {
'ApiKey': bundle.authData.ApiKey
}
};
return z.request(options).then((response) => {
response.throwForStatus();
const results = response.json;
const col = results.DatabaseColumns.filter((item) => item.IsCustom).map((item) => {
return {
...item,
id: item["ColumnName"],
};
});
return col});
That is what I am trying to use for the Action. I am using this same does for a Trigger and it works there, but not as Dynamic Field Option along with other standard inputs.
Not sure if I need to tweak the code or if I can invoke the data that the Trigger would pull?
Here is the visual of the fields, but I need it to pull and offer the custom fields. This would be like favorite color, etc.
Image of Zap
Any help is appreciated.
I was able to use this code:
// Configure a request to an endpoint of your api that
// returns custom field meta data for the authenticated
// user. Don't forget to congigure authentication!
const options = {
url: 'https://edapi.campaigner.com/v1/Database',
method: 'GET',
headers: {
'X-API-KEY': bundle.authData.ApiKey
},
params: {
'ApiKey': bundle.authData.ApiKey
}
};
return z.request(options).then((response) => {
response.throwForStatus();
const results = response.json;
var col = results.DatabaseColumns.filter((item) => item.IsCustom).map((item) => {
return {
...item,
key: item["ColumnName"],
value: item["ColumnName"]
};
});
//var col = col.filter(items => ['FirstName', 'LastName'].indexOf(items) >= 0 )
for (var i = col.length; i--;) {
if (col[i].key === 'FirstName' || col[i].key === 'LastName' ) {
col.splice(i, 1);
}
}
return col});
/*
return [
{
"key": "FirstName",
"value":"First Name"
},
{
"key": "LastName",
"value": "Last Name"
},
{
"key": "Test",
"value": "Test 2"
},
*/

Sequelize query with a where clause on an include of an include

I'm struggling to create a query with sequelize.
Some context
I have the following models:
A Manifestation can have [0..n] Event
An Event belongs to one Manifestation (an Event cannot exist without a Manifestation)
A Place can have [0..n] Event
An Event belongs to one Place (an Event cannot exist without a Place)
A Manifestation can have [1..n] Place
A Place can have [0..n] Manifestation
I model the relations as the following:
Manifestation.hasMany(Event, { onDelete: 'CASCADE', hooks: true })
Event.belongsTo(Manifestation)
Place.hasMany(Event, { onDelete: 'CASCADE', hooks: true })
Event.belongsTo(Place)
Manifestation.belongsToMany(Place, { through: 'manifestation_place' })
Place.belongsToMany(Manifestation, { through: 'manifestation_place' })
For me it seems rather correct, but don't hesitate if you have remarks.
The question
I'm trying to query the Place in order to get all Manifestation and Event happening in a given Place. But for the Event ones, I want to include them within their Manifestation even if the Manifestation doesn't happen in the given Place.
Below is the "JSON" structure I'm trying to achieve:
{
id: 1,
name: "Place Name",
address: "Place address",
latitude: 47.00000,
longitude: -1.540000,
manifestations: [
{
id: 10,
title: "Manifestation one",
placeId: 1,
events: []
},
{
id: 11,
title: "Manifestation two",
placeId: 3,
events: [
id: 5,
title: "3333",
manifestationId: 11,
placeId: 1
]
}
]
}
So I want to include the Manifestation with id: 11, because one of its Event occurs in the given Place (with id: 1)
Update (04/06/20): For now I rely on javascript to get the expected result
I figured out it would be nice if I posted my current solution before asking.
router.get('/test', async (req, res) => {
try {
const placesPromise = place.findAll()
const manifestationsPromise = manifestation.findAll({
include: [
{ model: event },
{
model: place,
attributes: ['id'],
},
],
})
const [places, untransformedManifestations] = await Promise.all([
placesPromise,
manifestationsPromise,
])
const manifestations = untransformedManifestations.map(m => {
const values = m.toJSON()
const places = values.places.map(p => p.id)
return { ...values, places }
})
const result = places
.map(p => {
const values = p.toJSON()
const relatedManifestations = manifestations
.filter(m => {
const eventsPlaceId = m.events.map(e => e.placeId)
return (
m.places.includes(values.id) ||
eventsPlaceId.includes(values.id)
)
})
.map(m => {
const filteredEvents = m.events.filter(
e => e.placeId === values.id
)
return { ...m, events: filteredEvents }
})
return { ...values, manifestations: relatedManifestations }
})
.filter(p => p.manifestations.length)
return res.status(200).json(result)
} catch (err) {
console.log(err)
return res.status(500).send()
}
})
But I'm pretty sure I could do that directly with sequelize. Any ideas or recommendations ?
Thanks
This is not optimum. But you can try it out:
const findPlace = (id) => {
return new Promise(resolve => {
db.Place.findOne({
where: {
id: id
}
}).then(place => {
db.Manefestation.findAll({
include: [{
model: db.Event,
where: {
placeId: id
}
}]
}).then(manifestations => {
const out = Object.assign({}, {
id: place.id,
name: place.name,
address: place.address,
latitude: place.latitude,
longitude: place.longitude,
manifestations: manifestations.reduce((res, manifestation) => {
if (manifestation.placeId === place.id || manifestation.Event.length > 0) {
res.push({
id: manifestation.id,
title: manifestation.id,
placeId: manifestation.placeId,
events: manifestation.Event
})
}
return res;
}, [])
})
})
resolve(out);
})
})
}
From this, you get all manifestations that assigned to place or have any event that assigns. All included events in the manefestations are assigned to the place.
Edit :
You will be able to use the following one too:
const findPlace = (id) => {
return new Promise(resolve => {
db.Place.findOne({
include: [{
model: db.Manefestation,
include: [{
model: db.Event,
where: {
placeId: id
}
}]
}],
where: {
id: id
}
}).then(place => {
db.Manefestation.findAll({
include: [{
model: db.Event,
where: {
placeId: id
}
}],
where: {
placeId: {
$not: id
}
}
}).then(manifestations => {
place.Manefestation = place.Manefestation.concat(manifestations.filter(m=>m.Event.length>0))
resolve(place);// or you can rename, reassign keys here
})
})
})
}
Here I take only direct manifestations in the first query. Then, manifestations that not included and concatenate.
I do not know if you figure it out by now. But the solution is provided below.
Search with Sequelize could get funny :). You have to include inside another include. If the query gets slow use separate:true.
Place.findAll({
include: [
{
model: Manifestation,
attributes: ['id'],
include: [{
model: Event ,
attributes: ['id']
}]
},
],
})
I tried to complete it in a single query but you will still need JavaScript to be able to get the type of output that you want.
(Note: πŸ’‘ You need manifestation which is not connected to places but should be included if a event is present of that place. The only SQL way to get that starts by doing a CROSS JOIN between all tables and then filtering out the results which will be a very hefty query)
I came up with this code(tried & executed) which doesn't need you to execute 2 findAll that fetches all data as what you are currently using. Instead it fetched only the data needed for final output in 1 query.
const places = await Place.findAll({
include: [{
model: Manifestation,
// attributes: ['id']
through: {
attributes: [], // this helps not get keys/data of join table
},
}, {
model: Event,
include: [{
model: Manifestation,
// attributes: ['id']
}],
}
],
});
console.log('original output places:', JSON.stringify(places, null, 2));
const result = places.map(p => {
// destructuring to separate out place, manifestation, event object keys
const {
manifestations,
events,
...placeData
} = p.toJSON();
// building modified manifestation with events array
const _manifestations = manifestations.map(m => {
return ({ ...m, events: [] })
});
// going through places->events to push them to respective manifestation events array
// + add manifestation which is not directly associated to place but event is of that manifestation
events.map(e => {
const {
manifestation: e_manifestation, // renaming variable
...eventData
} = e;
const mIndex = _manifestations.findIndex(m1 => m1.id === e.manifestationId)
if (mIndex === -1) { // if manifestation not found add it with the events array
_manifestations.push({ ...e_manifestation, events: [eventData] });
} else { // if found push it into events array
_manifestations[mIndex].events.push(eventData);
}
});
// returning a place object with manifestations array that contains events array
return ({ ...placeData, manifestations: _manifestations });
})
// filter `.filter(p => p.manifestations.length)` as used in your question
console.log('modified places', JSON.stringify(result, null, 2));

How can I write this code to be more efficient

I am learning Vue.js and I am setting up a website where I am using LocalStorage to store data.
I wrote some code, which is a little clunky and very repetitive:
<script>
const app = new Vue({
el:'#app',
data:{
explosive_pullups_1: '',
explosive_pullups_2: '',
explosive_pullups_3: '',
tuck_front_raises_1: '',
tuck_front_raises_2: '',
tuck_front_raises_3: '',
},
mounted() {
if (localStorage.explosive_pullups_1) {
this.explosive_pullups_1 = localStorage.explosive_pullups_1;
}
if (localStorage.explosive_pullups_2) {
this.explosive_pullups_2 = localStorage.explosive_pullups_2;
}
if (localStorage.explosive_pullups_3) {
this.explosive_pullups_3 = localStorage.explosive_pullups_3;
}
if (localStorage.tuck_front_raises_1) {
this.tuck_front_raises_1 = localStorage.tuck_front_raises_1;
}
if (localStorage.tuck_front_raises_2) {
this.tuck_front_raises_2 = localStorage.tuck_front_raises_2;
}
if (localStorage.tuck_front_raises_3) {
this.tuck_front_raises_3 = localStorage.tuck_front_raises_3;
}
},
watch: {
explosive_pullups_1(pullups1) {
localStorage.explosive_pullups_1 = pullups1;
},
explosive_pullups_2(pullups2) {
localStorage.explosive_pullups_2 = pullups2;
},
explosive_pullups_3(pullups3) {
localStorage.explosive_pullups_3 = pullups3;
},
tuck_front_raises_1(tuck_front_raises1) {
localStorage.tuck_front_raises_1 = tuck_front_raises1;
},
tuck_front_raises_2(tuck_front_raises2) {
localStorage.tuck_front_raises_2 = tuck_front_raises2;
},
tuck_front_raises_3(tuck_front_raises3) {
localStorage.tuck_front_raises_3 = tuck_front_raises3;
},
}
})
</script>
I would like to know a way to write this code to be less repetitive.
You can put the exercise data into its own object, and save that to localStorage instead. E.g.:
<script>
const app = new Vue({
el:'#app',
data: {
exercises: {},
},
mounted() {
this.exercises = JSON.parse(localStorage.getItem("exercises"));
},
watch: {
exercises(newExerciseValues) {
localStorage.setItem("exercises", JSON.stringify(newExerciseValues));
},
}
})
</script>
If you really need to store and retrieve the individual exercises explicitly, I would recommend keeping the data in one exercises object, and simply use a for loop to check/set everything. Something like this:
[...]
watch: {
exercises(newExercises) {
const exercisesToCheck = [
'explosive_pullups_1',
'explosive_pullups_2',
'explosive_pullups_3',
'tuck_front_raises_1',
'tuck_front_raises_2',
'tuck_front_raises_3',
];
for (const exercise of exercisesToCheck) {
localStorage.setItem(exercise, this.exercises[exercise]);
}
},
},
[...]
On a side note, be very careful when working with objects in Vue. If you need to add a new exercise to the exercises object, avoid using this.exercises['new_exercise'] = newExercise. Instead, use Vue.set(this.exercises, 'new_exercise', newExercise). Check out the Vue docs for an explanation.

dojox.mobile: Custom ListItem widget: "... is not a constructor"

I want to create a custom ListItem widget for my dojox.mobile app. It works if i use it in my HTML Code, but it throws a TypeError if i try to use it programmatically.
This is the JS-Code for my custom ListItem:
define([
"dojo/_base/declare",
"dojo/dom-construct",
"dojox/mobile/ListItem"], function(declare, domConstruct, ListItem){
var LabeledInputListItem = declare("myapp.LabeledInputListItem", ListItem, {
labelText: "",
placeholder: "",
value: "",
_setItemLabelAttr: function(val) {
this.labelText = val;
this.qDescSpan.innerHTML = val;
},
_setPlaceholderAttr: function(val) {
this.placeholder = val;
},
_setValueAttr: function(val) {
this.value = val;
},
startup: function(){
if(this._started){ return; }
},
constructor: function(params) {
this.placeholder = params.placeholder;
this.labelText = params.labelText;
this.valu = params.value;
},
buildRendering: function(){
this.inherited(arguments);
this.qDescDiv = domConstruct.create("div", {className: "tableItemDescription", id: "asd"}, this.labelNode, "before");
this.qDescSpan = domConstruct.create("span", null, this.qDescDiv, "first");
this.qInputDiv = domConstruct.create("div", {className: "tableItemInput"}, this.qDescDiv, "after");
this.qInputText = domConstruct.create("input", {className: "mblTextBox sessionTextbox", placeholder: this.placeholder, value: this.value}, this.qInputDiv, "first");
console.log(this.labelText, this.placeholder, this.value);
},
});
return LabeledInputListItem; });
I can use this custom ListItem in my html Code like this:
<li data-dojo-type="myapp/LabeledInputListItem" data-dojo-props="itemLabel: 'asdasd', placeholder: 'placeholder', value: 'value'"></li>
However, if I try to create my custom ListItem programmatically it results in the following error:
TypeError: myapp.LabeledInputListItem is not a constructor
var childWidget = new myapp.LabeledInputListItem({placeholder: "placeholder"});
Does anybody know what i'm missing?
Thanks in advance for your help!
The only (obvious) reason I can think of would be that you did not require the module?
By the way Dojo is now moving towards a "no globals" approach, so it may be better to not give an explicit id to your class, and use the value of the AMD module instead of the global myapp.LabeledInputListItem.