Can't display images sourced from GraphQL, error [gatsby-plugin-image] missing image prop - graphql

I'm trying to source content with images from Contentful into Gatsby but I failed to get images displayed.
I installed gatsby-transformer-sharp, gatsby-plugin-image, gatsby-plugin-sharp, gatsby-remark-images and gatsby-remark-images-contentful.
down below is a simple of my code
import { GatsbyImage, getImage } from "gatsby-plugin-image"
const Projects = ({ data }) => {
const projects = data.projects.nodes
return (
<Layout>
<Seo
title={"Projects"}
description={"Projects & Websites I've Developed"}
/>
<div className={styles.portfolio}>
<h1>My Portfolio</h1>
<h2>Projects & Websites I've Developed</h2>
<div className={styles.projects}>
{projects.map(project => (
<Link
to={"/projects/" + project.slug}
key={project.id}
className={styles.project}
>
<GatsbyImage
image={getImage(project.thumb)}
alt={project.title}
/>
<div className={styles.cardText}>
<h3>{project.title}</h3>
<p>{project.stack}</p>
</div>
</Link>
))}
</div>
</div>
</Layout>
)
}
export default Projects
export const query = graphql`
query ProjectsPage {
projects: allContentfulProjects(sort: { fields: date, order: DESC }) {
nodes {
key
slug
stack
title
thumb {
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
}
id
}
}
}
`
here what i got from GraphQL
{
"data": {
"projects": {
"nodes": [
{
"key": "project",
"slug": "portfolio-website",
"stack": "html - css - javascript",
"title": "Portfolio Website",
"thumb": [
{
"gatsbyImageData": {
"images": {
"sources": [
{
"srcSet": "https://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=750&h=361&q=50&fm=webp 750w,\nhttps://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1080&h=520&q=50&fm=webp 1080w,\nhttps://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1366&h=658&q=50&fm=webp 1366w,\nhttps://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1920&h=925&q=50&fm=webp 1920w",
"sizes": "100vw",
"type": "image/webp"
}
],
"fallback": {
"src": "https://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1920&h=925&q=50&fm=png",
"srcSet": "https://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=750&h=361&q=50&fm=png 750w,\nhttps://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1080&h=520&q=50&fm=png 1080w,\nhttps://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1366&h=658&q=50&fm=png 1366w,\nhttps://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1920&h=925&q=50&fm=png 1920w",
"sizes": "100vw"
}
},
"layout": "fullWidth",
"width": 1,
"height": 0.4817708333333333,
"placeholder": {
"fallback": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAMAAACDi47UAAABv1BMVEUaGhosLSN+gm9ORjIcHBwlJB8kJBgkJBclJBgeHRREORVFWEeEj5SNingqNys+x8tWzNFk1Nhq1dl42Nx51dp219xw19twxMhjyMxKys89x8wnZlw7MhUiIRtrKiRCLCBHys5bztJu1tuD2t501tp62N1519yokpF3b25My9A/yc4oZ10VFRUkJCQoKChHR0c1NTUqKSotOCxEw8dbxcllys1owcR30dR2z9Nyz9NkyM2+n52cjo0/wsc5vsMrXVNdTx2niSCnjCqniiOfgyAtOC1HsbVRq69errJcpah1y8982N1u1dpto7F7RlG7lpeLWXVFr7koYFYtKiJJQyxTTDZMRS9DPSssNytNk5VWf3VbfWVWdVlnsKxryc1ays+xJ06sCy2sCS2wCi2bJkYrXlUjIyMuLi48PDw0NDQsLCwrNyw6n6I/j5BJlZBJlJFavL5Xxco4v8XDEz+QCiSqCSuHCiCJDidhKS07OzszMzMeHRk4NSg7OCs5NSk5NSg6Nio5Nik7Nys6NyocGhI6OjkxMTEYGBgmJiUmJiYjJCQlJSUXFxcWFhYRERE0Lhw7NBxBORwpJRswMDA0NTUvbwraAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAB3RJTUUH5gUJBR4Qdhx/lQAAAGRJREFUCNeNzUEKglAAANEZ/5cgRLTO0ZWCTtS6jdfxEJ5BUNyF+FuIiNSit5zNiKuUAbBAMHLWqfQgctGJWsdqrze/9PH6Z+R3hNphe8z5HFIgQuFQqHbtHSVlyFN9n3w92DQfWKcTSK8wndgAAAAASUVORK5CYII="
what it might be wrong with My code? need some help :)

According to what you said in the comment section, I'd say that there's a position in projects that has no thumbnail defined (or not properly queried).
Try adding a condition wrapping the GatsbyImage display:
{project.thumb && <GatsbyImage
image={getImage(project.thumb)}
alt={project.title}
/>}
That said, check in which project you have no thumbnail.

Finally I have figured it out by
1- I removed all My content and images in Contentful CMS and create a fresh ones, It seemed there was a bug with sourcing Images into GraphQL where the Image src was always giving an empty array!!
2- Taking out getImage function and replace it with <GatsbyImage image={project.thumb.gatsbyImageData} alt={project.title}/>
,then gatsby clean to clear the .cashe and also triggered clean cashe and rebuild.
Now everything is works well.

Related

Wordpress Custom Widget Save Multiple Attributes?

I am using the #wordpress/create-block package to build a simple widget. I do not understand how to make the save.js save more than one attribute.
I have 2 attributes defined in the block.json: theNotes and theContact.
"attributes": {
"theNotes": {
"type": "string",
"source": "text",
"selector": "div",
"default": ""
},
"theContact": {
"type": "string",
"source": "text",
"selector": "div",
"default": ""
}
}
My edit.js looks like this:
export default function Edit( { attributes, setAttributes } ) {
return (
<div { ...useBlockProps() }>
<div>
<TextControl
label={ __( 'The Notes', 'editor-notes' ) }
value={ attributes.theNotes }
onChange={ ( val ) => setAttributes( { theNotes: val } ) }
/>
</div>
<div>
<TextControl
label={ __( 'The Contact', 'editor-notes' ) }
value={ attributes.theContact }
onChange={ ( val ) => setAttributes( { theContact: val } ) }
/>
</div>
</div>
);}
For the save.js file, I cannot find instructions on how to save both of those attributes using this default scaffolding. I thought something like this would work, but I get a block validation error. It says that both the attributes were saved twice to both attribute values.
export default function save( { attributes } ) {
const blockProps = useBlockProps.save();
return (
<div { ...blockProps }>
<div>{ attributes.theNotes }</div>
<div>{ attributes.theContact }</div>
</div>
); }
The error says:
Content generated by `save` function:
<div class="wp-block-create-block-editor-notes"><div>notesTestcontactTest</div><div>notesTestcontactTest</div></div>
Content retrieved from post body:
<div class="wp-block-create-block-editor-notes"><div>notesTest</div><div>contactTest</div></div>
The Getting Started Guide shows how to save one attribute called "message" like this. Apparently, I do not know what to do when I have multiple attributes to update:
import { useBlockProps } from '#wordpress/block-editor';
export default function save( { attributes } ) {
const blockProps = useBlockProps.save();
return <div { ...blockProps }>{ attributes.message }</div>;}
The error indicates an issue with the save() function; however this is a little misleading. The content mismatch between save and post body is actually caused by how the attribute selector in block.json is defined as "div" for both theNotes and theContact.
Given the attributes selector defined is not a unique element (<div>...</div> appears 3 times in the saved content), the method used to extract data from the post content gets multiple matches so both attributes save the text content of <div> and <div> again. This results in the "notesTestcontactTest" text seen in the error message.
block.json (current)
"attributes": {
"theNotes": {
"type": "string",
"source": "text", // the value saved for theNotes is the text
"selector": "div", // within this matching selector
"default": ""
},
"theContact": {
"type": "string",
"source": "text", // the value save for theContact is the text
"selector": "div", // with the same matching selector as theNotes
"default": ""
}
}
By adding a unique class name to div selector of both attributes, the values will save and update correctly, eg:
block.json (updated)
"attributes": {
"theNotes": {
"type": "string",
"source": "text",
"selector": "div.the-notes", // a div with the className "the-notes"
"default": ""
},
"theContact": {
"type": "string",
"source": "text",
"selector": "div.the-contact", // a div with the className "the-contact"
"default": ""
}
}
The RichText component would be more suitable than using TextControl for editing content to be saved as text of block-level elements like <div>, eg:
edit.js
import { useBlockProps, RichText } from '#wordpress/block-editor';
export default function Edit( { attributes, setAttributes } ) {
return (
<div { ...useBlockProps() }>
<RichText
tagName="div" // Output as a <div>, no extra div needed
value={ attributes.theNotes }
onChange={ ( content ) => setAttributes( { theNotes: content } ) }
placeholder="Enter Notes.." // Optional
/>
<RichText
tagName="div" // Output as a <div>, no extra div needed
value={ attributes.theContact }
onChange={ ( content ) => setAttributes( { theContact: content } ) }
placeholder="Enter Contact.." // Optional
/>
</div>
)
}
The save() function would then also need updating to ensure the attributes selector finds the right match to extract the props.attributes values. RichText.Content can be used in save to render the tags markup and content:
save.js
import { useBlockProps, RichText } from '#wordpress/block-editor';
export default function save( { attributes } ) {
const blockProps = useBlockProps.save();
return (
<div { ...blockProps }>
<RichText.Content
tagName="div"
className="the-notes" // Used for the selector
value={ attributes.theNotes }
/>
<RichText.Content
tagName="div"
className="the-contact" // Used for the selector
value={ attributes.theContact }
/>
</div>
)
}
The RichText tagName could also be another block-level element like "h2" or "p" as long as the attributes selector matches. When retesting these changes to your block, remove the previous block from the Editor, save, refresh/clear the cache then insert your block again. To confirm the attributes save corrently, in the Editor use the Code view to see the markup that will be saved, it should be something like:
<!-- wp:create-block/editor-notes -->
<div class="wp-block-create-block-editor-notes"><div class="the-notes">Notes Test</div><div class="the-contact">Contact Test</div></div>
<!-- /wp:create-block/editor-notes -->

How do I render my results using graphql in Vuejs

I am learning graphql and using strapi as a backend nuxt as a front end
I have set up the backend and am now trying to display the results
I have the following code, it is returning the results but I cannot for the life of me figure out how to display just the name field, can you assist
<template>
<div>
<!-- Events are displayed here -->
<div
v-for='organisation in organisations'
:key='organisation.id'
>
test {{ organisation }}
</div>
</div>
</template>
<script>
import gql from "graphql-tag";
export default {
data() {
return {
};
},
apollo: {
organisations: gql`
query organisations {
organisations {
data {
attributes {
name
}
id
}
}
}`
}
};
</script>
returns
test [ { "attributes": { "name": "Organisation 1", "__typename": "Organisation" }, "id": "1", "__typename": "OrganisationEntity" }, { "attributes": { "name": "test2", "__typename": "Organisation" }, "id": "2", "__typename": "OrganisationEntity" } ]
test OrganisationEntityResponseCollection
if i try {{ organisation.name }} it returns no error but nothing displayed, if I try {{ organisation.attributes.name }} i get an error
Thanks
Ah, I should have had
v-for='organisation in organisations.data'
in my v-for, now working

Vue3 apollo displaying query results using composition API

So I am using vue router and trying to display the graphql results on my page.
Here is the router link on index.js
{
path: '/clients/:id',
name: 'client_profile',
component: () => import('../views/client_profile.vue')
},
The link to the page is from a table with this code using the router-link, where an id is passed as a param:
<router-link :to="{ name:'client_profile', params: { id: data.id }}"> {{data.name}}
</router-link>
The dynamic link looks like this on the setup(), where the useQuery loads my query clientEntity:
setup(){
const route = useRoute(),
id = computed(() => route.params.id)
const { result } = useQuery(clientEntity,{
id: id.value,
})
const client = computed(() => result.value?.entities[0])
return{
client,
result
}
}
On the HTML if I put in {{client}} or {{result}} I get the following:
//results
{ "entities": [ { "address": "555 Fake Street", "name": "Test1", "notes": "", "phone": null } ] }
//client
{ "address": "555 Fake Street", "name": "Test1", "notes": "", "phone": null }
But if I try accessing some of the data like {{client.address}} or {{client.name}} the page turns blank and I get the following error:
[Vue warn]: Unhandled error during execution of render function
at <BaseTransition appear=false persisted=false mode=undefined ... >
at <Transition name="p-toggleable-content" >
at <Panel header="Description" toggleable=true style=
Object { "text-align": "left" }
>
at <ClientProfile onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > >
at <RouterView>
at <App>
at <App>

Styling in Adaptive Card Submit Action

I am using Adaptive card to display some items in my bot solution.
In Adaptive card Submit button i want to make title as bold.
Code:
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"body": [
{
"maxLines": 0,
"size": "default",
"spacing": "medium",
"text": "You can ask me below optons",
"type": "TextBlock",
"weight": "default",
"wrap": true
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Service details \n \"Service details for PC request\"",
"data": "Service details for PC request"
}
],
"type": "AdaptiveCard",
"version": "1.0"
}
In the above code.I am showing title in submit button two lines.
In this i want to make only "Service details" in bold.
Is there any option for submit action styling?
I have tried Bold(** {Something} **) option. But didnt work for Button title.
Unfortunately, it appears that rendering Markdown is not supported by Adaptive Cards for the action component. As you can see in the AC docs, Markdown is only supported in the TextBlock. Scrolling down to Actions, you can see that it is not.
If this is a feature you feel strongly about, I would suggest you create a feature request on their GitHub repo.
[Edit]
It is possible to change the text of the button after the card has been passed to Web Chat but prior to its rendering. Add the following code, making adjustments where necessary, and you should be good to go.
mainDialog.js - Pass placeholder text in the adaptive card being sent from the bot.
async basicAdaptiveCard ( stepContext ) {
let text = `##Service details` // \n \"Service details for PC request\""
let response = md.utils.isString( '__Service details__' )
const card = {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"text": "Hi!! How can I help you today?",
"weight": "Bolder",
"size": "Medium"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Placeholder Message", // This text will be replaced in Web Chat
"data": "close"
}
]
}
index.html
<head>
[...]
<script type="text/javascript" src="https://unpkg.com/markdown-it#8.4.2/dist/markdown-it.min.js"></script>
[...]
</head>
[...]
<script type="text/babel">
( async function () {
'use strict';
const { ReactWebChat } = window.WebChat;
const markdownIt = window.markdownit(); // Import 'markdown-it' into web chat script
[...]
// Create `store` to capture and modify the activity coming from the bot
const store = window.WebChat.createStore( {}, ( { dispatch } ) => next => async action => {
// Notifies Web Chat we are going to do something when an activity is received from the bot
if ( action.type === 'DIRECT_LINE/INCOMING_ACTIVITY' ) {
// We update the HTML of the already rendered card.
// First, we acquire the button(s). In my case, I have multiple buttons from multiple cards, so I gather them all.
let button = document.body.getElementsByClassName('ac-pushButton')
// Next, we cycle through the buttons
for(let i = 0; i <= button.length - 1; i++) {
// Looking for the button with the text we passed through
if(button[i].children[0].nodeName === 'DIV' && button[i].children[0].innerHTML === 'Placeholder Message') {
// As the default font-weight for the button is bold, we set it all to 'normal'
button[i].children[0].setAttribute('style', 'font-weight: normal; color: black')
// And pass in the text we want with the styling we want allowing us to specify which text should be bold
button[i].children[0].innerHTML = '<p><b>Service details</b><br />\"Service details for PC request\"</p> '
continue;
}
}
return next( action );
} );
// Finally, we pass in `store` to the renderer
window.ReactDOM.render(
<ReactWebChat
directLine={ directLine }
store={store}
/>,
document.getElementById( 'webchat' )
);
document.querySelector( '#webchat > *' ).focus();
Hope of help.

inline video Integration issue in openx and flowplayer

I am using following jquery live click to display ad from my openx server.
$('.vbox > li > img').live('click',function(){
var videourl = "http://www.indiantripadviser.com/img/video/"+$(this).data('videourl');
var videodur = parseInt($(this).data('duration'));
$('#vidHolder').show();
flowplayer("player", "dist/swf/flowplayer-3.2.7.swf", {
"playlist":[
{
"url": videourl,
"duration": videodur
}
],
"plugins": {
"ova": {
"url": "dist/swf/ova.swf",
"autoPlay": true,
"ads": {
"controls": {
"skipAd": {
"enabled": true,
"showAfterSeconds": 5,
"image": "global/images/skip.png",
"width": 100,
"height": 15
}
},
"servers": [
{
"type": "OpenX",
"apiAddress": "http://advert.visionimpact.co.in/www/delivery/fc.php"
}
],
"schedule": [
{
"zone": "8",
"position": "pre-roll"
}
],
"notice": { "type": "countdown" }
}
}
},
"canvas": {
"backgroundColor": '#F9F9F9'
}
});
});
Now my issue is, if I use the "apiAddress": "http://advert.indiantripadviser.com/www/delivery/fc.php" it works fine but when i change it to "apiAddress": "http://advert.**visionimpact.co.in**/www/delivery/fc.php" it stops delivering ads. I can't figure out where is the mistake, as I created, linked the zone and banner several times.
I am totally out!
Looks like a crossdomain issue. Have you allowed
http://advert.**visionimpact.co.in**
in your crossdomain xml file?
If you are serving your ads from a different domain name than the flash player, you need to install a crossdomain.xml file in the docroot on your openX ad server to allow flash to communicate to it.
Example crossdomain xml :
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
Ref : http://code.google.com/p/openx-iab-vast/wiki/ExampleCrossdomainXML

Resources