Cannot format nested date field in keystone.js - javascript

I am extending keystone.js to support multiple languages in the models.
The original model looks like this:
Post.add({
title: { type: String, required: true },
publishedDate: { type: Types.Date, index: true },
//... more irrelevant fields
});
My extended model looks like this:
Post.add({
title: { type: String, required: true },
en: {
title: { type: String },
publishedDate: { type: Types.Date, index: true },
//... more irrelevant fields
},
es: {
title: { type: String },
publishedDate: { type: Types.Date, index: true },
//... more irrelevant fields
},
//... more languages following the same pattern
});
I am having an issue using the nested publishedDate properties within the view templates.
Original view code that works with the original model:
{% if post.publishedDate %}
<br>on {{ post._.publishedDate.format('MMMM DD, YYYY') }}
{% endif %}
Adjusted view code for my new model (this is where I am having the issue):
{% if post[lang].publishedDate %}
<br>on {{ post[lang]._.publishedDate.format('MMMM DD, YYYY') }}
{% endif %}
Using post[lang].xxxxxx I can refer to all of the other items in my post (for example post[lang].title.
Am I missing something that is causing these nested underscore functions to fail with the following error?
non_object_property_load Error thrown for request" /en/blog
TypeError: Cannot read property 'publishedDate' of undefined
EDIT:
It gets more peculiar... below seems to work:
{% if post[lang].publishedDate %}
<br>on {{ post._[lang].publishedDate.format('MMMM DD, YYYY') }}
{% endif %}
If anyone can offer up an explanation of why this works (or a better way to accomplish this), I would really appreciate it.

#JRulle, I assume the error is on the following line:
<br>on {{ post[lang]._.publishedDate.format('MMMM DD, YYYY') }}
The issue is that the underscore methods belong to the List object. For example, to access the underscore methods for post.en.publishedDate you would use the following syntax: post._.en.publishedDate.format('MMMM DD, YYYY')
You should change the above line to:
<br>on {{ post._[lang].publishedDate.format('MMMM DD, YYYY') }}

Related

Displaying binary data in a HBS view from MongoDB - Node js

I have a hbs view which is receiving and displaying some data that I am pulling from MongoDB.
It is displaying all my data correctly except for the binary data which I am using inside of an img element. If I copy the binary data from the MongoDB document and put it in the img element it displays in the browser. For this reason I feel that the variable I am referencing is incorrect?
I have also tried to use 'img.$binary' and that does not show any data at all.
This would seem to me the way to do it though with 'img' being an object?
But when I log 'img' to the console it seems to be the right one. When I log 'img.$binary' it is undefined. I am definitely getting some data in the img tag as it shows this when I run node js (with 'img' in the appropriate place in hbs view):
HTML:
My route:
router.get('/', async (req, res) => {
const products = await Product.find()
res.render('shop', {
title: 'Shop',
products: products
})
})
Mongoose Model:
const ProductSchema = new mongoose.Schema(
{
title: { type: String, required: true, unique: true },
desc: { type: String, required: true },
img: { type: Buffer },
categories: { type: Array },
size: { type: String },
colour: { type: String },
price: { type: Number, required: true },
},
{ timestamps: true }
)
MongoDB Collection:
{
"_id" : ObjectId("62dd1127884e20dcfbb09a6c"),
"title" : "'Northface tshirt'",
"desc" : "'test'",
"img" : { "$binary" : "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6CAIAAAAH...(shortened for viewability), "$type" : "00" },
"categories" : [],
"size" : "'XL'",
"colour" : "'White'",
"price" : 80,
"createdAt" : ISODate("2022-07-24T09:30:15.974Z"),
"updatedAt" : ISODate("2022-07-24T09:30:15.974Z"),
"__v" : 0
}
HBS view:
<body>
<div class="grid-wrapper">
{{!-- Object --}}
{{#each products}}
<div class="grid-number">
<img src="data:image/jpg;base64,{{img}}">
{{!-- String --}}
<h2>{{title}}</h2>
{{!-- Array --}}
{{#each categories}}
{{!-- Strings --}}
<p>Apparel Type: {{apparelType}}</p>
<p>Gender: {{gender}}</p>
{{/each}}
<p>Size: {{size}}</p>
<p>Price: {{price}}</p>
<p>Colour: {{colour}}</p>
</div>
{{/each}}
</div>
Any help would be greatly appreciated, I have searched for a couple hours now and seen some similar issues but nothing has helped so far. Hoping someone with more experience with data will know what is going wrong here. Thanks in advance.
Not exactly an answer for inserting the binary data straight into the img tag but I have now found a way to display the DB document images dynamically.
Firstly, I added a route to view the img for each document in the collection by it's id:
//VIEW PRODUCT IMG
router.get('/:id/img', async (req, res) => {
try {
const product = await Product.findById(req.params.id)
if (!product || !product.img) {
throw new Error()
}
res.set('Content-Type', 'image/jpg')
res.send(product.img)
} catch (e) {
res.status(404).send()
}
})
Then, modified my img src attribute to point towards the route + inserted the id's of the documents dynamically in the hbs template:
<div class="grid-wrapper">
{{!-- Object --}}
{{#each products}}
<div class="grid-number">
<img src="products/{{id}}</img">
{{!-- String --}}
<h2>{{title}}</h2>
{{!-- Array --}}
{{#each categories}}
{{!-- Strings --}}
<p>Apparel Type: {{apparelType}}</p>
<p>Gender: {{gender}}</p>
{{/each}}
<p>Size: {{size}}</p>
<p>Price: {{price}}</p>
<p>Colour: {{colour}}</p>
</div>
{{/each}}
</div>
I can now display the images as intended:

Mustache issue with array of objects

So I searched for similar question and I applied their answers but it doesn't seem to work in my case. It's frustrating 'cause it should be something simple.
So, I use mustache template to render data that come from a node server with sockets.
It works fine with one object but when I try to iterate through an array of object it just render a blank page.
This is my socket, the push is just to simulate what I'm gonna do next (get a new object in the array)
let productsTab = [{
prodName: prodName,
prodPrice: prodPrice,
quantity: quantity,
quantityUnit: quantityUnit,
isQuantityManual: isQuantityManual,
hasQuantityUnit: hasQuantityUnit,
totalPrice: totalPrice
}];
productsTab.push({
prodName: prodName,
prodPrice: prodPrice,
quantity: quantity,
quantityUnit: quantityUnit,
isQuantityManual: isQuantityManual,
hasQuantityUnit: hasQuantityUnit,
totalPrice: totalPrice
});
res.render('displayProduct', productsTab);
this is the log of my array
[
{
prodName: 'name',
prodPrice: 'price',
quantity: '1',
quantityUnit: '',
isQuantityManual: false,
hasQuantityUnit: false,
totalPrice: 'price'
},
{
prodName: 'name',
prodPrice: 'price',
quantity: '1',
quantityUnit: '',
isQuantityManual: false,
hasQuantityUnit: false,
totalPrice: 'price'
}
]
And finally this is my mustache template
{{#productsTab}}
<div>
<div>
{{ prodName}}
</div>
<div>
{{{ prodPrice }}}
{{ #hasQuantityUnit }}
text
{{ /hasQuantityUnit }}
</div>
</div>
<div>
<div>
x {{ quantity }} {{ quantityUnit }}
{{ #isQuantityManual }}
(MAN)
{{ /isQuantityManual }}
</div>
<div>
= {{{ totalPrice }}}
</div>
</div>
{{/productsTab}}
It works fine with just an object (not an array) without the {{#}} loop feature so the issue must come from the array...
I need some help please
Ok, I got it. It is when I render my template
res.render('displayProduct', productsTab);
This works only when the props you pass is an object but I had to iterate through an array of object so I did this :
res.render('displayProduct', { productsTab });
Hope it will help someone that got a brain freeze like me.

nunjucks fetch data from input

I am trying to retrieve below field values in nunjucks following below template
Json data -
{
"user": {
"custom": [
{
"payload": "{ f_name=user, l_name=name, source=facebook, contact=email }"
}
]
}
}
Nunjucks Template -
{% set u = user %}
{% set data = u['custom'][0]['payload'] %}
Hello {{ data }}
This returns the below output
Hello { f_name=user, l_name=name, source=facebook, contact=email }
However, I would like to get the individual elements from the {{data}}
How can I fetch the f_name, l_name, source, contact fields from the above json data.
Please note the payload is a string and not a json object
You don't show us how user is pulling your JSON data into nunjucks, so I'll just spill out my take on this. Take advantage of the JavaScript split method, and the template engine loops and filters to give you the results you need.
I'm assuming there is more to your JSON data. If so, here is a short guide to help pull your 4 string items out of payload.
The JSON Data:
//sample JSON Data
const sampleData = [{
"user": {
"custom": [{
"payload": "{ f_name=user, l_name=name, source=facebook, contact=email }"
}]
}
}];
module.exports = sampleData;
The View:
{% for string in mSampleData %} //mSampleData is similar to your "user" template object.
{% for mval in string['user']['custom'] %}
{% set mstring = mval['payload'].replace('{', '').replace('}', '') %}
{% set marray = mstring.split(",") %}
{% set fname = marray[0].replace('f_name=', '') %}
{% set lname = marray[1].replace('l_name=','') %}
{% set source = marray[2].replace('source=','') %}
{% set contact = marray[3].replace('contact=','') %}
<p>{{fname}}</p>
<p>{{lname}}</p>
<p>{{source}}</p>
<p>{{contact}}</p>
{% endfor %}
{% endfor %}
The results:
user
name
facebook
email

Fullcalendar Event save on click - Django

I suppose that this is pretty simple to someone who knows JavaScript, but I just can't figure it out on my own.
I've implemented FullCalendar into my Django application, and what I want is simple Event save on users click(saving events to the database after user's action, after the click release and drawn event).
I can add an event using Django form, and have no problem with that, but I want to save the event on click, as I said before. So the user clicks on the desired time, draw the event 'bubble' and let the click off. So when that event is drawn, it needs to be saved directly to the database or passed to the Django form.
I don't have much experience in JS so please don't mind me.
Thank you in advance.
PS: I repeat, everything works fine, I can add an event, delete it, etc, but only with my form.
Let's start with the zakazi.html (page where all the events are created) :
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% load static %}
{% block title %} Zakaži {% endblock title %}
{% block content_row %}
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
{{ form.media }}
{% include 'main/partials/_link_fullcalendar.html' %} # all the cdn's for fullcalendar(link tags)
<div style="display: flex; width: 100%; margin: 0 auto;text-align: center">
<div class="container" style="width: 350px;">
<div class="row">
<div class="col">
<form method="post" action="{% url 'main:add_event' opp.pk %}">
{{ form|crispy }}
{% csrf_token %}
<button type="submit" class="btn btn-primary">Potvrdi</button>
</form>
</div>
</div>
</div>
<div class="container"
style="display: flex; overflow-x: scroll; height: 750px; width: max-content;">
{% if calendars %}
{% for cal in calendars %}
<script>
document.addEventListener('DOMContentLoaded', function () {
let calendarEl = document.getElementById('{{ cal.id }}');
//////////////////////////////////////////////////////////////////////////////////////////////
let calendar1 = new FullCalendar.Calendar(calendarEl, {
minTime: "07:00:00",
maxTime: "22:00:00",
businessHours: {
startTime: '09:00', // a start time (10am in this example)
endTime: '21:00', // an end time (6pm in this example)
},
height: 'auto',
locale: 'sr',
plugins: ['dayGrid', 'timeGrid', 'list', 'interaction'],
defaultView: 'timeGridDay',
header: {
left: 'today',
center: '{{ cal.name|title }}',
right: 'timeGridDay,dayGridWeek,timeGridThreeDay'
},
views: {
timeGridThreeDay: {
type: 'timeGrid',
duration: {days: 3},
buttonText: '3 Dana'
}
},
navLinks: false, // can click day/week names to navigate views
select: function (arg) {
let title = prompt('Naziv posla');
if (title) {
calendar.addEvent({
title: title,
start: arg.start,
end: arg.end,
allDay: arg.allDay
})
}
calendar.unselect()
},
editable: true,
selectable: true,
selectMirror: true,
eventLimit: true, // allow "more" link when too many events
eventTextColor: 'black',
events: [
{% for i in events %}
{% if i.calendar_id == cal.id %}
{
id: "{{ i.event_id }}",
calendar: "{{ i.calendar }}",
calendar_id: "{{ i.calendar_id }}",
title: "{{ i.event_name}}",
start: '{{ i.start_date|date:"Y-m-d" }}T{{ i.start_date|time:"H:i" }}',
end: '{{ i.end_date|date:"Y-m-d" }}T{{ i.end_date|time:"H:i" }}',
},
{% endif %}
{% endfor %}
]
});
//////////////////////////////////////////////////////////////////////////////////////////////
calendar1.render();
//////////////////////////////////////////////////////////////////////////////////////////////
})
;
</script>
{% endfor %}
{% endif %}
<div style="display: flex; height: 1000px" class="container">
{% for cal in calendars %}
<p>{{ cal.name|title }}{{ cal.id }}</p>
<div class="container" id='{{ cal.id }}'></div>
{% endfor %}
</div>
</div>
</div>
<!---------------------------------------------- FULLCALENDAR SCRIPT----------------------------------------------->
{% include 'main/partials/_fullcalendar_script.html' %}
<!---------------------------------------------- FULLCALENDAR SCRIPT END ------------------------------------------>
{% endblock content_row %}
My views.py (all_events and add_events functions):
#################################################### EVENTS #########################################################
def events(request):
all_events = Events.objects.all()
get_event_types = Events.objects.only('event_type')
calendars = Calendar.objects.all()
if request.GET:
event_arr = []
if request.GET.get('event_type') == "all":
all_events = Events.objects.all()
else:
all_events = Events.objects.filter(event_type__icontains=request.GET.get('event_type'))
for i in all_events:
event_sub_arr = {}
event_sub_arr['id'] = i.event_id
event_sub_arr['calendar'] = i.calendar
event_sub_arr['calendar_id'] = i.calendar.id
event_sub_arr['title'] = i.event_name
start_date = datetime.strptime(str(i.start_date.date()), "%Y-%m-%dT%H:%M:%S").strftime("%Y-%m-%dT%H:%M:%S")
end_date = datetime.strptime(str(i.end_date.date()), "%Y-%m-%dT%H:%M:%S").strftime("%Y-%m-%dT%H:%M:%S")
event_sub_arr['start'] = start_date
event_sub_arr['end'] = end_date
event_arr.append(event_sub_arr)
return HttpResponse(json.dumps(event_arr))
context = {
"calendars": calendars,
"events": all_events,
"get_event_types": get_event_types,
}
return render(request, 'main/selectable.html', context)
################################################## ADD EVENTS #########################################################
def add_event(request, pk):
opp = get_object_or_404(OpportunityList, pk=pk)
events_all = Events.objects.all()
calendars = Calendar.objects.all()
opp_locked = get_object_or_404(Locked, pk=pk)
user = User.objects.get(username=request.user.username)
form = AddEventForm()
if request.method == 'POST':
form = AddEventForm(request.POST or None)
if form.is_valid():
event = Events.objects.create(
event_name=form.cleaned_data['event_name'],
event_comment=form.cleaned_data['event_comment'],
status=form.cleaned_data['status'],
start_date=form.cleaned_data['start_date'],
end_date=form.cleaned_data['end_date'],
calendar=form.cleaned_data['calendar'],
opp_eluid=int(opp_locked.locked_eluid.eluid),
zakazan=True,
added_by=user,
)
opp_locked.opp_comment = form.cleaned_data['event_comment']
opp_locked.is_locked = False
opp_locked.zakazan = True
opp_locked.save()
event.save()
messages.success(request, '...' + opp_locked.opp_comment)
return redirect('opportunity:optika')
context = {
'form': form,
'opp': opp,
'events': events_all,
"calendars": calendars
}
return render(request, 'opportunity/detalji/zakazi.html', context) # html for adding events to calendar, where the form is
And the form :
class ZakaziForma(forms.ModelForm):
class Meta:
model = Events
fields = ['event_name', 'event_comment', 'status', 'start_date', 'end_date', 'calendar',
'opp_eluid']
labels = {
'event_name': 'Naziv Posla:',
'event_comment': 'Komentar:',
'status': 'Status:',
'start_date': 'Početak:',
'end_date': 'Završetak:',
'calendar': 'Kalendar',
}
widgets = {
'start_date': DateTimePicker(options={'useCurrent': True, 'collapse': False},
attrs={'icon-toggle': True, }),
'end_date': DateTimePicker(options={'useCurrent': True, 'collapse': False}),
'opp_eluid': forms.HiddenInput(),
}
My urls :
...
path('calendar/dodaj/<int:pk>', add_event, name='add_event'),
...
I think you are trying this in a too complex way. If you use fullcalender and jquery you can just add something like the following in you script code:
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay',
},
defaultView: 'agendaWeek',
navLinks: true,
selectable: true,
selectHelper: true,
select: function(start, end) {
title='new';
if (title) {
eventData = {
title: title,
start: start,
end: end,
backgroundColor: '#00ff00',
};
$('#calendar').fullCalendar('renderEvent', eventData, true); // stick? = true
}
$.ajax({ url: '/addevent/',
data: {
'start': start,
'end': end,
},
});
;
...here you need to addd the code that draws the events
So what happens is that JS renders the event in the browser and sends the data via an ajax call to the django server. Of course you need to add the ajax view in your urls and views code.

How to include javascript inside form widget in Symfony2

I would like to include JavaScript inside a form widget in Symfony2, but quotes are escaped inside the JavaScript command, see:
{{ form_widget(form.sdf,
{ 'attr': { 'value': "document.MSketch.getMol('sdf');" } }
) }}
and the result I get:
<input type="hidden" id="form_sdf" name="form[sdf]" required="required" value="document.MSketch.getMol('sdf');" />
I have read this topic : Twig and autoescaping
But autoescape false is not working when using it like this:
{% autoescape false %}
{{ form_widget(form.sdf,
{ 'attr': { 'value': "document.MSketch.getMol('sdf');" } }
) }}
{% endautoescape %}
How to have quotes?
EDIT: Using raw filter isn't helping:
{% set cmd = 'document.MSketch.getMol("sdf");' %}
{{ form_widget(form.sdf, { 'attr': { 'value': cmd|raw } } ) }}
But raw filter is working outside of the form_widget, so where is the problem?
Have you tried to simply escape quotes? \' or \"

Categories

Resources