Nunjucks: Can I combine, concatenate or update a JSON object? - nunjucks

Is it possible to amend, update, combine, concatenate or otherwise join 2 bits of JSON in Nunjucks?
Here's an example: I'm trying to add an element to an existing variable. (The element can exist as an empty string, but I can't find a way to update that either..)
Given this JSON stucture:
{
type: "radio",
items: [
{
value: "yes",
text: "Yes"
},
{
value: "no",
text: "No"
}
]
}
I then want to add the following error element so I have:
{
type: "radio",
items: [
{
value: "yes",
text: "Yes"
},
{
value: "no",
text: "No"
}
],
error: {
message: "Some message. This could be empty to start with and updated somehow too"
}
}
This is the closest I've managed to get..
{# index.njk #}
{% set question = {
type: "radio",
items: [
{
value: "yes",
text: "Yes"
},
{
value: "no",
text: "No"
}
]
}
%}
{{ question | dump }}
<hr>
{# now I want to add or update a value in that JSON variable.. #}
{% set question = question + {
error: {
message: "some error message"
}
}
%}
{{ question | dump }}
{# outputs: "[object Object][object Object]" #}
{# desired output: { "type": "radio" .... , "error": "some error message" } #}

You can do the following if you can create the question after the error message:
{% set errorMessage = { message: "some error message" } %}
...
{% set question = {
type: "radio",
items: [
{
value: "yes",
text: "Yes"
},
{
value: "no",
text: "No"
}
],
error: errorMessage
}
%}

Related

Easy problem: Unable to output the yml data with liquid

I have a problem very similar to this one, but unfortunately, the solution doesn't work for me. So I'm posting another question.
I'm making a website with Jekyll and would like to print the information of a yml file on a page or post. Here is a dummy yml file:
- Master student:
- Dummy name1:
- email: blabal#bla.com
- room: 1
- tel: 12345678
- Bachelor student:
- Dummy name:
- email: blabal#bla.com
- room: 12
- tel: 0987654
- Guest:
- Bird:
- email: blabal#bla.com
- room: 10856
- tel: 71864270
This file is placed in a newly made _data directory, under the name people.yml. Then, I made a new post on a freshly made site with the minimal theme, which goes as follows:
---
layout: post
title: "Test"
date: 2023-01-12 23:42:09 +0100
---
{% assign people = site.data.people | read_yaml %}
<!-- {{ people }} --> // this tests if the files is loaded or not
{% for role in people %}
{% assign role_data = role[1] %}
{{ role_data[0] }} has the following role: {{ role[0] }}.
{% endfor %}
Once I generate the site, I expect the following text on the post (except maybe for some linebreaks):
Dummy name1 has the following role: Master student
Dummy name has the following role: Bachelor student
Bird has the following role: Guest
Instead, I get this:
has the following role: .
has the following role: .
has the following role: .
that puzzles me. I suspect the reason is the way I access the item values. But can't figure it out. Removing the read_yml also seems to have no effect.
You were on the right track, but didn't do enough un-nesting of your hashes. The data structure is a bit unfortunate; maybe when you look at the equivalent JSON, it's more obvious:
[
{
"Master student": [
{
"Dummy name1": [
{
"email": "blabal#bla.com"
},
{
"room": 1
},
{
"tel": 12345678
}
]
}
]
},
{
"Bachelor student": [
{
"Dummy name": [
{
"email": "blabal#bla.com"
},
{
"room": 12
},
{
"tel": 987654
}
]
}
]
},
{
"Guest": [
{
"Bird": [
{
"email": "blabal#bla.com"
},
{
"room": 10856
},
{
"tel": 71864270
}
]
}
]
}
]
So, each array element is a hash (object), and to get key and value, you have to iterate over the hashes; the values themselves are again arrays of hashes. This snippet produces your desired output:
{% assign people = site.data.people %}
{% for person in people %}
{%- for person_hash in person %}
{%- assign role = person_hash[0] %}
{%- for role_hash in person_hash[1][0] %}
{{- role_hash[0] }} has the following role: {{ role }}.
{% endfor %}
{% endfor %}
{% endfor %}
I would recommend you re-structure your data, to something like this:
- role: Master student
name: Dummy name1
email: blabal#bla.com
room: 1
tel: 12345678
- role: Bachelor student
name: Dummy name
email: blabal#bla.com
room: 12
tel: 0987654
- role: Guest
name: Bird
email: blabal#bla.com
room: 10856
tel: 71864270
which corresponds to this JSON:
[
{
"role": "Master student",
"name": "Dummy name1",
"email": "blabal#bla.com",
"room": 1,
"tel": 12345678
},
{
"role": "Bachelor student",
"name": "Dummy name",
"email": "blabal#bla.com",
"room": 12,
"tel": 987654
},
{
"role": "Guest",
"name": "Bird",
"email": "blabal#bla.com",
"room": 10856,
"tel": 71864270
}
]
Then, iterating over it becomes as simple as this:
{% for person in site.data.people %}
{{ person.name }} has the following role: {{ person.role }}
{% endfor %}

Dry validation i18n message for array validation

Let say I have define a dry-validation like this:
class ApplicationContract < Dry::Validation::Contract
config.messages.backend = :i18n
config.messages.load_paths << 'config/errors.yml'
params do
required(:todo).schema do
required(:title).filled(:string)
required(:items).array(:hash) do
required(:name).filled(:string)
end
end
end
end
Here is my config/errors.yml:
vi:
dry_validation:
errors:
rules:
title:
filled?: 'phai duoc dien'
key?: 'ko dc trong'
items:
name:
key?: 'thieu name'
filled?: 'name rong'
In my code, I use it to validate my data:
my_json = create_my_json
v = ApplicationContract.new
result = v.call(my_json)
render json: result.errors(locale: :vi).to_h
If my_json like:
{
"title": "",
"items": [
{
"name": "bbb"
}
]
}
then I got response:
{
"todo": {
"title": [
"phai duoc dien"
]
}
}
You guys can see my validation for field title works fine with locale vi
Now if my json like:
{
"title": "aa",
"items": [
{
"name": ""
}
]
}
then the response is:
{
"todo": {
"items": {
"0": {
"name": [
"translation missing: vi.dry_validation.errors.filled?"
]
}
}
}
}
The validation still works but it can not get my locale message. It show the warning "translation missing: vi.dry_validation.errors.filled?" instead. How can I fix this problem?
Finally I got it. Just remove the node items from config/errors.yml:
vi:
dry_validation:
errors:
rules:
title:
filled?: 'phai duoc dien'
key?: 'ko dc trong'
name:
key?: 'thieu name'
filled?: 'name rong'

ansible: Invalid data passed to 'loop'

I have this following playbook, which gather facts in google cloud and filter instance names we want.
tasks:
- name: get tags
delegate_to: localhost
gcp_compute_instance_info:
auth_kind: serviceaccount
service_account_file: "xxx"
zone: "xxx"
filters:
- "name:{{ names }}*"
project: "{{ project }}"
register: ilist
- name: Display output
debug: var=ilist['items']
- set_fact:
instances: "{{ instances|default([]) + [ item.name ] }}"
loop: "{{ ilist['items']}}"
when: item.name is regex(".*"+tag+"-[a-z0-9]{4}$")
- debug:
var: instances
I'm getting following error in the loop task
Invalid data passed to 'loop', it requires a list, got this instead:
<built-in method items of dict object at 0x7fe0f370aa70>. Hint: If you
passed a list/dict of just one element, try adding wantlist=True to
your lookup invocation or use q/query instead of lookup.
what I'm doing wrong here? thanks
and this is the output of ilist
{
"changed":false,
"failed":false,
"resources":[
{
"canIpForward":false,
"cpuPlatform":"Intel Haswell",
"creationTimestamp":"2020-09-14T04:05:58.316-07:00",
"deletionProtection":false,
"disks":[
{
"autoDelete":true,
"boot":true,
"deviceName":"persistent-disk-0",
"diskSizeGb":"10",
"guestOsFeatures":[
{
"type":"VIRTIO_SCSI_MULTIQUEUE"
}
],
"index":0,
"interface":"SCSI",
"kind":"compute#attachedDisk",
"licenses":[
"xxxx"
],
"mode":"READ_WRITE",
"source":"xxxx",
"type":"PERSISTENT"
}
],
"fingerprint":"3yOdLl6Hp8g=",
"id":"3503717950118097018",
"kind":"compute#instance",
"labelFingerprint":"IP52FxBvsW0=",
"labels":{
"block":"internal",
"component":"dev",
"function":"internal"
},
"lastStartTimestamp":"2020-09-14T04:06:26.016-07:00",
"machineType":"xxxx",
"metadata":{
"fingerprint":"sTp1wPeotCo=",
"items":[
{
"key":"instance-template",
"value":"xxxx
},
{
"key":"created-by",
"value":"xxxx"
}
],
"kind":"compute#metadata"
},
"name":"test-vm",
"networkInterfaces":[
{
"fingerprint":"ae26IqBpxVo=",
"kind":"compute#networkInterface",
"name":"nic0",
"network":"xxxx",
"networkIP":"xxxx"
}
],
"scheduling":{
"automaticRestart":true,
"onHostMaintenance":"MIGRATE",
"preemptible":false
},
"selfLink":"xxxxx",
"serviceAccounts":[
{
"email":"xxxx",
"scopes":[
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring.write",
"https://www.googleapis.com/auth/pubsub",
"https://www.googleapis.com/auth/service.management.readonly",
"https://www.googleapis.com/auth/servicecontrol",
"https://www.googleapis.com/auth/trace.append"
]
}
],
"startRestricted":false,
"status":"RUNNING",
"tags":{
"fingerprint":"Oyf1u-BGqNA=",
"items":[
"no-ip-b"
]
},
"zone":"xxxx"
},
{
"canIpForward":false,
"cpuPlatform":"Intel Haswell",
"creationTimestamp":"2020-10-15T06:59:52.505-07:00",
"deletionProtection":false,
"disks":[
{
"autoDelete":true,
"boot":true,
"deviceName":"persistent-disk-0",
"diskSizeGb":"10",
"guestOsFeatures":[
{
"type":"VIRTIO_SCSI_MULTIQUEUE"
}
],
"index":0,
"interface":"SCSI",
"kind":"compute#attachedDisk",
"licenses":[
"xxxx"
],
"mode":"READ_WRITE",
"source":"xxxxx",
"type":"PERSISTENT"
}
],
"fingerprint":"-E0UpLFggow=",
"id":"5900118287465179960",
"kind":"compute#instance",
"labelFingerprint":"IP52FxBvsW0=",
"labels":{
"block":"internal",
"component":"dev",
"function":"internal"
},
"lastStartTimestamp":"2020-10-15T07:00:37.895-07:00",
"machineType":"xxxxx",
"metadata":{
"fingerprint":"05Oj3Bq6zb4=",
"items":[
{
"key":"instance-template",
"value":"xxxx"
},
{
"key":"created-by",
"value":"xxxx"
}
],
"kind":"compute#metadata"
},
"name":"test-vm",
"networkInterfaces":[
{
"fingerprint":"H24HFGkCFNg=",
"kind":"compute#networkInterface",
"name":"nic0",
"network":"xxxx",
"networkIP":"xxxx"
}
],
"scheduling":{
"automaticRestart":true,
"onHostMaintenance":"MIGRATE",
"preemptible":false
},
"selfLink":"xxxx",
"serviceAccounts":[
{
"email":"xxxx",
"scopes":[
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring.write",
"https://www.googleapis.com/auth/pubsub",
"https://www.googleapis.com/auth/service.management.readonly",
"https://www.googleapis.com/auth/servicecontrol",
"https://www.googleapis.com/auth/trace.append"
]
}
],
"startRestricted":false,
"status":"RUNNING",
"tags":{
"fingerprint":"Oyf1u-BGqNA=",
"items":[
"no-ip-b"
]
},
"zone":"xxxx"
}
]
}
You can try with the query function
loop: {{ query('dict', ilist.items) }}

Gridsome source-filesystem add tag description

I'm using #gridsome/source-filesystem with this config:
{
use: '#gridsome/source-filesystem',
options: {
typeName: 'Post',
path: 'content/posts/**/*.md',
refs: {
tags: {
typeName: 'Tag',
create: true
},
author: {
typeName: 'Author',
create: true
}
}
},
}
Now I want to add description for one tag only, so I created a new doc in content/posts/my-tag.md:
---
title: Tag-Title
description:tag description
---
How can I connect this document to the allTags collection?
Or any other way (without #gridsome/source-filesystem for Tags, for example), to add description to exists node in collection?
If you want to just add allTags, you can create markdown for it.
in gridsome.config.js
...
{
use: '#gridsome/source-filesystem',
options: {
path: 'content/tags/**/*.md',
typeName: 'Tag'
},
}
...
add file content/tags/my-tag.md
---
title: Tag-Title
description: tag description
---
you can explole
{
allTag {
edges {
node {
id
title
description
}
}
}
}
{
"data": {
"allTag": {
"edges": [
{
"node": {
"id": "******", // random hash
"title": "Tag-Title",
"description": "tag description"
}
},
{
"node": {
"id": "foo",
"title": "foo",
"description": ""
}
},
...
but, this is not able to connect to your Post.
or just added description to Tag, you can use addSchemaResolvers.
in gridsome.server.js
module.exports = function(api) {
api.loadSource(async ({ addSchemaResolvers }) => {
addSchemaResolvers({
Tag: {
description: {
type: "String",
resolve(obj) {
if (!obj.description) {
// coding your logic
return "set description";
} else {
return obj.description;
}
}
}
}
});
});
};

Return a random value to data in field value is blank

I'm working on a redirect generator using 11ty and netlify-cms, and storing data in a shorturls.json file.
My config.yml looks like this:
collections:
- name: "config"
label: "Admin"
description: "Administer site settings"
create: false
editor:
preview: false
files:
- label: short urls
name: shorturls
file: "_src/_data/shorturls.json"
widget: "object"
fields:
- label: "Short urls"
label_singular: "Short url"
name: "go"
widget: "list"
fields:
- { label: "From", name: "from", widget: "string", required: false }
- { label: "To", name: "to", widget: "string" }
- { label: "Redirect type", name: "status", widget: "hidden", default: "301" }
My json structure looks like this:
{
"go": [
{
"from": "/here",
"to": "/there"
},
{
"to": "/from-random"
}
]
}
Is there a way to populate a random value to the from field? Is this going to need to be a custom widget?
The json output should then look something like this:
{
"go": [
{
"from": "/here",
"to": "/there"
},
{
"from": "/e6y0p13l",
"to": "/from-random"
}
]
}
Thanks

Resources