Using Handlebars for conditional CSS - handlebars.js

In the snippet below I'd expect row a to have the class new-entry and row c to have the class moving-up but neither does.
I'm certain this is a silly mistake but I can't see it
Handlebars.registerHelper("newEntry", function() {
return this.newEntry ? 'class="new-entry"' : '';
});
Handlebars.registerHelper("movingUp", function() {
return this.movingUp ? 'class="moving-up"' : '';
});
var source = document.getElementById('leaderboard-template').innerHTML;
var template = Handlebars.compile(source);
var outlet = document.getElementById('outlet');
outlet.innerHTML = template({leaders: [
{name: 'a', signature_count: 10, newEntry: true},
{name: 'b', signature_count: 8},
{name: 'c', signature_count: 6, movingUp: false},
]});
.new-entry {
background-color:red;
}
.moving-up {
color:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.6/handlebars.min.js"></script>
<script id="leaderboard-template" type="text/x-handlebars-template">
<table>
<thead>
<th>Constituency</th>
<th>Votes</th>
</thead>
<tbody>
{{#leaders}}
<tr {{newEntry}}>
<td>{{name}}</td>
<td><span {{movingUp}}>{{signature_count}}</span></td>
</tr>
{{/leaders}}
</tbody>
</table>
</script>
<div id="outlet"></div>

Handlebar converts the return value of a helper to an HTML escaped string. Use Handlebars.SafeString like this if you don't want that:
Handlebars.registerHelper("newEntry", function() {
return new Handlebars.SafeString( this.newEntry ? 'class="new-entry"' : '' );
});
Handlebars.registerHelper("movingUp", function() {
return new Handlebars.SafeString( this.movingUp ? 'class="moving-up"' : '' );
});

Related

Symfony 4 x-editable - update

My mission is to use the x-editable library for bootstrap in Symfony 4.
After clicking on the field in the table appears "input" and the value from the field inside. I have a problem to make an update to the database. In the code below I am doing an update to the database with a fixed value of "Koralik". I would like the update with the value from "input" to go to the base.
<table id="tab1" class="table table-bordered table-striped table-hover">
<thead style="color:blue;">
<tr><th>Imię</th><th>Nazwisko</th></tr>
</thead>
<tbody id="myTable">
{%for kierowca_one in kierowca%}
<tr class="text-success">
<td>{{kierowca_one.Imie}}</td>
<td><span class="myElement" data-type="text" data-pk="
{{kierowca_one.id}}" data-url="{{path('app_update',
{id:kierowca_one.id})}}">{{kierowca_one.Nazwisko}}</span> </td>
</tr>
{%endfor%}
</tboody>
</table>
$('.myElement').editable({
type: "POST",
emptytext: 'Brak',
showbuttons: false,
mode: 'inline',
//dataType: 'json',
validate: function(value){
if($.trim(value) == '')
{
return 'This field is required';
}
}
});
/**
* #Route("/update/{id}", name="app_update", methods={"GET"})
* #IsGranted("ROLE_USER")
*/
public function updateMethod(EntityManagerInterface $em, $id)
{
$repository=$em->getRepository(Kierowcy::class);
$kierowca=$repository->find($id);
$kierowca->setNazwisko('Kowalik');
$em->persist($kierowca);
$em->flush();
return new Response();
}
here is my approach.
js file
$('#s').editable({
selector: '.js-editable',
url: urlUpdateTopic,
params:function(params){
params.pk = $(this).closest('tr').data('id');
return params;
},
success: function(value, response) {
if(response){
$(this).html(value);
}
},
error: function(response) {
if(response.status === 500) {
console.log('Service unavailable. Please try later.');
} else {
console.log(response.responseText);
}
},
type: 'text',
pk: 1,
mode: 'inline',
showbuttons: false,
toggle: 'dblclick',
onblur: "submit",
clear: false,
emptytext: ''
});
here is controller
public function updateTopicAction(Request $request)
{
$id = $request->request->get('pk');
$value = $request->request->get('value');
}
also you can see a good example here Submitting data via Ajax in X-Editable

Rocket Chat Filter changes with result set

I am updating the rocket chat app to have a departments filter on the department list page. I am running into an issue where my filter seems to be tied to the same collection as the result set. So when I update the filter all the other filter options are removed. I'm not sure the best way to make it so the filter only impacts the result list and not both.
Before:
After:
HTML
<template name="livechatDepartments">
{{#requiresPermission 'view-livechat-manager'}}
<fieldset>
<form class="form-inline" method="post">
<div class="form-group">
<label for="department">{{_ "Department"}}</label>
<select name="department">
<option value=""></option>
{{#each departmentsDDL}}
<option value="{{_id}}">{{name}}</option>
{{/each}}
</select>
</div>
<div class="form-group">
<label for="agent">{{_ "Served_By"}}</label>
<select name="agent">
<option value=""></option>
{{#each agents}}
<option value="{{_id}}">{{username}}</option>
{{/each}}
</select>
</div>
<button class="button">{{_ "Filter"}}</button>
</form>
</fieldset>
<div class="list">
<table>
<thead>
<tr>
<th width="20%">{{_ "Name"}}</th>
<th width="30%">{{_ "Description"}}</th>
<th width="10%">{{_ "Num_Agents"}}</th>
<th width="10%">{{_ "Num_Available_Agents"}}</th>
<th width="20%">{{_ "Enabled"}}</th>
<th width="20%">{{_ "Show_on_registration_page"}}</th>
<th>{{_ "Delete"}}</th>
</tr>
</thead>
<tbody>
{{#each departments}}
<tr class="department-info row-link" data-id="{{_id}}">
<td>{{name}}</td>
<td>{{description}}</td>
<td>{{numAgents}}</td>
<!--<td>{{}}</td>-->
<td>{{#if enabled}}{{_ "Yes"}}{{else}}{{_ "No"}}{{/if}}</td>
<td>{{#if showOnRegistration}}{{_ "Yes"}}{{else}}{{_ "No"}}{{/if}}</td>
<td><i class="icon-trash"></i></td>
</tr>
{{/each}}
</tbody>
</table>
</div>
<div class="text-center">
<button class="button load-more">{{_ "Load_more"}}</button>
</div>
{{_ "New_Department"}}
{{/requiresPermission}}
JS:
Template.livechatDepartments.helpers({
departmentsDDL() {
return LivechatDepartment.find({}, { sort: { name: -1 } });
},
departments() {
return LivechatDepartment.find({}, { sort: { name: -1 } });
},
agents() {
return AgentUsers.find({}, { sort: { name: 1 } });
}
});
Template.livechatDepartments.events({
'click .remove-department' (e /*, instance*/ ) {
e.preventDefault();
e.stopPropagation();
swal({
title: t('Are_you_sure'),
type: 'warning',
showCancelButton: true,
confirmButtonColor: '#DD6B55',
confirmButtonText: t('Yes'),
cancelButtonText: t('Cancel'),
closeOnConfirm: false,
html: false
}, () => {
Meteor.call('livechat:removeDepartment', this._id, function(error /*, result*/ ) {
if (error) { return handleError(error); }
swal({
title: t('Removed'),
text: t('Department_removed'),
type: 'success',
timer: 1000,
showConfirmButton: false
});
});
});
},
'click .department-info' (e /*, instance*/ ) {
e.preventDefault();
FlowRouter.go('livechat-department-edit', { _id: this._id });
},
'submit form' (e, instance) {
e.preventDefault();
const filter = {};
$(':input', event.currentTarget)
.each(function() {
if (this.name) {
filter[this.name] = $(this)
.val();
}
});
instance.filter.set(filter);
instance.limit.set(20);
}
});
Template.livechatDepartments.onCreated(function() {
this.limit = new ReactiveVar(20);
this.filter = new ReactiveVar({});
this.subscribe('livechat:agents');
this.autorun(() => {
this.subscribe('livechat:departments', this.filter.get(), 0, this.limit.get());
});
});
Meteor Method:
Meteor.publish("livechat:departments", function(filter = {}, offset = 0, limit = 20) {
if (!this.userId) {
return this.error(
new Meteor.Error("error-not-authorized", "Not authorized", {
publish: "livechat:agents"
})
);
}
if (!RocketChat.authz.hasPermission(this.userId, "view-l-room")) {
return this.error(
new Meteor.Error("error-not-authorized", "Not authorized", {
publish: "livechat:agents"
})
);
}
check(filter, {
agent: Match.Maybe(String), // agent _id who is serving
department: Match.Maybe(String)
});
const query = {};
if (filter.agent) {
const DepartmentFilter = [];
RocketChat.models.LivechatDepartmentAgents
.find({
agentId: filter.agent
})
.forEach(department => {
DepartmentFilter.push(department);
});
var depts = DepartmentFilter.map(function(dep) {
return dep.departmentId;
});
As you stated in the question, your filter is tied to the same collection as your results set. So, how can you fix this?
Solution 1 - Easy, and if data in livechat:departments collection is not too large, probably the best:
Revert back your subscription code to fetch all data (not filtered), and filter in the departments helper function
// in Template.livechatDepartments.onCreated
this.subscribe('livechat:departments');
// in Template.livechatDepartments.helpers
departments() {
const departmentFilter = Template.instance().filter.get().department;
if (departmentFilter){
return LivechatDepartment.find({name: departmentFilter }, { sort: { name: -1 } });
}
else {
return LivechatDepartment.find({}, { sort: { name: -1 } });
}
}
Solution 2 - Keep departments helper with filter from Solution 1 ,
but now subscribe twice to livechat:departments
You can reuse the current publish for the filtered list of departments (add back your filtered subscription), and create a new pub/sub channel that publishes all the departments, but only needs to send the name + _id fields used to populate select options.

How to use template helper to return a modified value of a field of table

In my mongo database i have number to defined the statut of the member, what I want to do is to get the name for this number, I did the function.
But i don't know how to use it with blaze.
In my html I have this :
{{#each usersList}}
<tr>
<td contenteditable="true">{{profile.firstName}}</td>
<td contenteditable="true">{{profile.lastName}}</td>
<td contenteditable="true">{{emails.[0].address}}</td>
<td contenteditable="true">{{profile.statut}}</td>
<td contenteditable="true">{{profile.subject}}</td>
<td contenteditable="true">{{profile.roles}}</td>
</tr>
{{/each}}
And in my js i have this :
Template.manageMember.helpers({
usersList : Meteor.users.find(),
'usersList.profile.statut': function(){
return userRightGetNameFromId(this);
}
});
I did that :
'usersList.profile.statut': function(){
return userRightGetNameFromId(this);
}
I understood, what i have i to is simply that :
in my helper:
userRightIdToName: function(context, options) {
if(context)
return userRightGetNameFromId(context);
}
And in my html:
<td contenteditable="true">{{emails.[0].address}}</td>
<td contenteditable="true">{{userRightIdToName profile.statut}}</td>
<td contenteditable="true">{{profile.subject}}</td>
But, I have a last problem with my function, it's return undefined, what can i do ?
This code is working, i have the number:
if(context)
return context;
}
My function:
userRightGetNameFromId = function(id){
$.each(USER_RIGHT, function(key, item) {
if (item.NUM == parseInt(id))
{
return item.NAME;
}
});
}
And my table:
USER_RIGHT =
{
STUDENT_1:
{
NUM: 1,
NAME: 'First'
},
STUDENT_2:
{
NUM: 2,
NAME: 'Second'
},
TUTOR:
{
NUM: 3,
NAME: 'Tutor'
},
RC:
{
NUM: 4,
NAME: 'RC'
},
RM:
{
NUM: 5,
NAME: 'RM'
},
RT:
{
NUM: 6,
NAME: 'RT'
},
ADMIN:
{
NUM: 7,
NAME: 'Admin'
}
};
Meteor doesn't wait that the function is finished ?

Meteor search clear results

I would like to make Meteor clear the last query, it does not accumulate my research. If I search in the input "Nº Património" and then doir again in the "Código Informática", I want to clear the first query results. What is happening is that it brings together the first and the second query results. Summing up, i want to se query results independently.Meteor search page
Template
<tbody>
<tr>
<th>Nº Património</th>
<th>Equipamento</th>
<th>Utilizador</th>
<th>Nº Helpdesk</th>
<th>Data Aquisição</th>
<th>Data Saída</th>
<th>Ultima Alteração</th>
</tr>
{{#each pesquisaEquipamentos}}
<tr>
<td>
{{npatrimonio}}
</td>
<td>
{{equipamento}}
</td>
<td>
{{utilizadores}}
</td>
<td>
{{helpdesk}}
</td>
<td>
{{daquisicao}}
</td>
<td>
{{dsaida}}
</td>
<td>
{{createdAt}}
</td>
</tr>
{{/each}}
</tbody>
Helper
if (Meteor.isClient) {
Template.pesquisar.helpers({
pesquisaEquipamentos: function() {
return Equipamentos.find();
}
});
Template.pesquisar.events({
"keypress input": function(event, template) {
if (event.keyCode == 13) {
var search = {};
search.value = event.target.value
search.name = event.target.name
//console.log(search.name, search.value);
Meteor.subscribe("pesquisaEquipamentos", search);
event.target.value = '';
}
}
});
}
Publication
Meteor.publish("pesquisaEquipamentos", function(search) {
//console.log(search.name);
//console.log(search.value);
switch (search.name) {
case 'npatrimonio':
return Equipamentos.find({
npatrimonio: search.value
});
break;
case 'cinformatica':
return Equipamentos.find({
cinformatica: search.value
});
break;
default:
}
});
Try stopping the subscription before you call it again:
var mySub;
Template.pesquisar.events({
"keypress input": function(event, template) {
if (event.keyCode == 13) {
var search = {};
search.value = event.target.value
search.name = event.target.name
if ( mySub ) mySub.stop(); // if you've previously subscribed clear those results
mySub = Meteor.subscribe("pesquisaEquipamentos", search);
event.target.value = '';
}
}
});

Table sorting causing duplication in meteor

In my meteor app I have a table of data with sorting for each coloumn. When I keep on clicking the coloumn for sorting, the table itself is getting multiplied.
This is the code for setting session variables.
'click #coloumn_name' : function()
{
var oldOrder = Session.get("sortOrder");
var sortField = 'coloumn1';
Session.set("sortField",sortField );
if(oldOrder == 1)
{
var newOrder = -1;
Session.set("sortOrder",newOrder );
}
else
{
var newOrder = 1;
Session.set("sortOrder",newOrder );
}
}
Here is the code for reading the session variables and fetching data from db.
Template.templatename.vname = function()
{
var filter = {sort: {}};
var sortField = Session.get('sortField');
var sortOrder = Session.get('sortOrder');
if(!sortField)
{
sortField = 'coloumn2';
}
if(!sortOrder)
{
sortOrder = 1;
}
filter.sort[sortField] = sortOrder;
return Groups.find({}, filter);
}
Here is my template
<template name="templatename">
<table>
<tr>
<th>Group Name</th>
<th>Status</th>
</tr>
{{#each vname }}
<tr>
<td> {{name}} </td>
<td> {{status}} </td>
</tr>
{{/each}}
</table>
</template>
This is the table before trying to sort.
This is the image after trying to sort
Does anyone have any idea why this happens ?

Resources