Firebase + VueJS: Highlighting data in a v-for loop - firebase

I am making a user- / login- / authentication-system with Firebase and VueJS.
I wonder how to highlight the name of each person that is online (has an entry in my firebase-sessions-list).
My database-structure:
for users:
- users:
- [userKey]:
- ... user information
for sessions:
- sessions:
- [userKey]:
- ... session information
The template part:
<table>
<tr class="user" v-for="user in $store.state.authentication.users">
<td class="name">{{ user.name }}</td>
...
</tr>
</table>
Advice?

You may add a class to td if user is online
<table>
<tr class="user" v-for="user in $store.state.authentication.users">
<td class="name" v-bind:class="getUserStatusClass(user)">
{{ user.name }}
</td>
...
</tr>
</table>
You also have to add a method to vue instance, like
methods: {
getUserStatusClass: function (user) {
if(// userKey is in sessons) {
return 'active'
}
return ''
}
},
A 'active' CSS class will be added to td if user is online. Than you can edit the style for 'active' CSS class

Related

How should i use if else and for loop with .hbs file (Handlebars.js)?

I know how can i use if else statement or for loop using .ejs file but i need to change code in .hbs file and i am new with this.Please help me with below example in which i have used .ejs file i need to convert it in .hbs file but don't know how to change if else and for loop
<!DOCTYPE html>
<html lang="en">
<head>
<title>Fetch using MySQL and Node.js</title>
</head>
<body>
<div class="table-data">
<h2>Display Data using Node.js & MySQL</h2>
<table border="1">
<tr>
<th>S.N</th>
<th>Full Name</th>
<th>Email Address</th>
<th>City</th>
<th>Country</th>
<th>Edit</th>
<th>Delete</th>
</tr>
<%
if(userData.length!=0){
var i=1;
userData.forEach(function(data){
%>
<tr>
<td><%=i; %></td>
<td><%=data.fullName %></td>
<td><%=data.emailAddress %></td>
<td><%=data.city %></td>
<td><%=data.country %></td>
<td>Edit</td>
<td>Delete</td>
</tr>
<% i++; }) %>
<% } else{ %>
<tr>
<td colspan="7">No Data Found</td>
</tr>
<% } %>
</table>
</div>
</body>
</html>
I have used below code but it is not working as i am new i need your guidence
#76484 i have used this ``` {{#if userData.length != 0 }}
{{var i =1;}}
{{userData.forEach(function(data))}}
<tr>
<td>{{=i;}}</td>
<td>{{= data.fullName}}</td>
<td>{{= data.emailAddress}}</td>
<td>{{= data.city}}</td>
<td>{{= data.country}}</td>
<td>{{= data.Dimension_4_Score}}</td>
<td>{{= data.Total_Score_Persentage}}</td>
</tr>
{{i++; })}}
{{else{} }
<tr>
<td colspan="7">No Data Found</td>
</tr>
{{}}}
</table>
</div>
</body> ``` but it is not working
The primary difference between your embedded JS example and Handlebars is that Handlebars does not execute arbitrary JavaScript, like your .forEach loop. Instead, Handlebars provides helpers to allow you to do things like conditionals and iteration.
First, we will tackle your condition, if (userData.length != 0). Handlebars has a #if helper which we could use to check if userData has a truth (greater than 0) length. The result would be:
{{#if userData.length}}
{{! TODO: output each user data}}
{{else}}
<tr>
<td colspan="7">No Data Found</td>
</tr>
{{/if}}
Secondly, Handlebars has an #each helper which is used for looping over collections as you are doing with your userData.forEach(function(data) { /*...*/ } code. For your purposes, the syntax would be:
{{#each userData}}
<tr>
<td>{{ #index }}</td>
<td>{{ fullName }}</td>
<td>{{ emailAddress }}</td>
<td>{{ city }}</td>
<td>{{ country }}</td>
<td>Edit</td>
<td>Delete</td>
</tr>
{{/each}}
Notice how we are evaluating the properties of each object in our userData array. There is no =. We just wrap the property name in double-handlebars, like {{ fullName }}. Handlebars handles the execution context within the #each so that we are always referring to the current iteration of our array.
Also notice the {{ #index }}. This is a special variable provided by Handlebars to give us the current iteration index within our #each loop. It is zero-index, so our output will be slightly different from your ejs example because you initialized your counter at 1.
Unfortunately, if we want our indexes to be one-based, we will have to write a custom helper to this. Our helper would just need to take a number, #index, and increment it by 1. It would look like:
Handlebars.registerHelper('increment', function (num) {
return num + 1;
});
And we would update our template to make use of it:
{{increment #index }}
I have created a fiddle with the final example for your reference.

Update only a single property of a given object

I have an entity called worker and each worker has a property called active which is boolean.
My twig is an index that shows the list of workers with active=true.
I have a button in front of each worker, when I press this button I want it to change that worker's active property to false.
The problem: I couldn't figure out how to change that value in the controller without making a form since I'm still an amateur when it comes to Symfony
Here's my twig:
<table id="file_export" class="table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last name</th>
<th>Active</th>
<th>edit</th>
</tr>
</thead>
<tbody>
{% for worker in workers %}
<tr>
<td>{{ worker.id }}</td>
<td>{{ worker.Firstname }}</td>
<td>{{ woker.Lastname }}</td>
<td>{{ worker.active ? 'active' : 'inactive' }}</td>
<td>
<i class="fa fa-pencil"></i>
</td>
</tr>
{% endfor %}
</tbody>
</table>
and my controller (which doesn't work):
/**
* #Route("/{id}/edit", name="worker_edit", methods={"GET","POST"})
*/
public function edit(Request $request, Worker $worker): Response
{
if ($this->isCsrfTokenValid('edit'.$worker->getId(), $request->request->get('_token'))) {
$worker->setActive(false);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($worker);
$entityManager->flush();
}
return $this->redirectToRoute('index');
}
you actually have to add a csrf token to your path call:
path('worker_edit', {'id': worker.id, '_token': csrf_token('worker'~worker.id)})
or otherwise your check for the csrf token obviously cannot succeed.
however, since a link will trigger a GET request, you have to look into
$request->query->get('_token')
in the isCsrfTokenValid call.
As a hint: give your routes and actions semantically better names. Like ... "worker_deactivate", if it is used to deactivate a worker (which it apparently is). it's also quite common, to call the routed methods of a controller actionAction, so that would be deactivateAction.
If you want to make HTTP requests without reloading the web page, then you've to go for AJAX calls. A very simple implementation using fetch that doesn't require any additional packages (like jQuery) would look like this:
<script>
(function() {
document.getElementById({{worker.id}}).addEventListener('click', function(e) {
e.preventDefault();
fetch({{path('worker_edit', {'id': worker.id})}}, {method: 'POST'})
.then(function(response) {
// you can catch eventual errors here, and of course refresh your button or display a nice message..
});
});
})()
</script>
<table id="file_export" class="table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last name</th>
<th>Active</th>
<th>edit</th>
</tr>
</thead>
<tbody>
{% for worker in workers %}
<tr>
<td>{{ worker.id }}</td>
<td>{{ worker.Firstname }}</td>
<td>{{ woker.Lastname }}</td>
<td>{{ worker.active ? 'active' : 'inactive' }}</td>
<td>
<i class="fa fa-pencil"></i>
</td>
</tr>
{% endfor %}
</tbody>
</table>
p.s: The javascript code above is not tested as I have to reproduce the twig and controller, but it could give you an idea on how to achieve the task.

Symfony 4, Twig & VueJS - Redirecting to Symfony routes in Vue component

I am getting started with Symfony 4 using Twig templating and VueJS for UI components.
I have a very basic component in a .vue file for listing tasks, which currently renders a basic table.
// task-list.vue
<template>
<div>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>
Task
</th>
<th>
Description
</th>
<th>
Completed?
</th>
</tr>
</thead>
<tbody>
<tr v-for="task in parsedTasks">
<td>
{{ task.title }}
</td>
<td>
{{ task.description }}
</td>
<td>
{{ task.completed ? 'Yes' : 'No' }}
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name: 'task-list',
props: {
tasks: {required: true}
},
computed: {
parsedTasks() {
return JSON.parse(this.tasks);
}
},
};
</script>
This component is registered in the root JS file;
// assets/js/app.js
Vue.component('task-list', TaskList);
new Vue({
el: '#app-root'
});
This is then used in a Twig template;
// tasks/list.html.twig
...
<task-list tasks="{{ tasks | json_encode }}"></task-list>
...
I want to be able to use the path() Twig function so that, when a row in the task list is clicked, the user is redirected to the generated route/path. Is this possible given that the Vue component is not in a Twig file?
As a side question, is there a better way to pass a Twig variable to a Vue component than json encoding then parsing the data as above?
There is two main approaches:
Generate the URL in the backend and use it in javascript:
var route = "{{ path('blog_show', {'slug': 'my-blog-post'})|escape('js') }}";
https://symfony.com/doc/current/routing/generate_url_javascript.html
Or using a javascript routing library that integrates with symfony routes like FOSJsRouting:
var url = Routing.generate('blog_show', {
'slug': 'my-blog-post'
});
https://github.com/FriendsOfSymfony/FOSJsRoutingBundle

How to highlight a selected row in *ngFor?

I couldn't find something that will help me to solve this issue in Angular2. I'd like to set a css class when I select a row. (without using jQuery)
<table class="table table-bordered table-condensed table-hover">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Website</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of companies" (click)="selectedCompany(item, $event)">
<td>{{item.name}}</td>
<td>{{item.email}}</td>
<td>{{item.website}}</td>
</tr>
</tbody>
</table>
I'm using Angular2 final release
There are plenty of solutions to do this, one of them is you can store the current company when clicked.
In the *ngFor you check if the current item is the currentCompany and you add the class highlighted or whatever class you wish if its the same company.
export class TableComponent {
public currentCompany;
public selectCompany(event: any, item: any) {
this.currentCompany = item.name;
}
}
And then on your template:
<tr *ngFor="let item of companies" (click)="selectCompany($event, item)"
[class.highlighted]="item.name === currentCompany">
--
Another solution if you wish to have multiple highlighted companies you can add a property highlighted to your item. Then on selectCompany() you just set the property to true. On your check you do [class.highlighted]="item.highlighted".
I know this was answered a while ago, but to expand on the accepted answer, you could also use [ngClass]="{'class_name': item.id === currentCompany }". The table hover may need to be removed as it may hide the background color change
<tr *ngFor="let item of companies" (click)="selectCompany($event, item)" [ngClass]="{'class_name': item.id === currentCompany }" >
Then css
.class_name{ background-color: yellow; }

Auto-print the fields of a Meteor collection using helpers without specifying their name

Is it possible to auto-print the fields of a Meteor collection using helpers without specifying them?
Let's say I start having a helper that returns the collection of objects stored in a table, as follows:
{{ #each CollectionData }}
<thead>
<tr>
<th>Code</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<Tr class="object-row">
<Td> {{code}} </ td>
<Td> {{description}} </ td>
</tr>
</tbody>
...
{{/each}}
Now i specify an "object schema" for each collection to set which field i want to auto-print, pseudo example:
// Items is the name of the possible collection
Schema.items var = {
fields {
code: {
columnName: "code",
show: false,
},
description: {
columnName: "description",
show: false,
},
otherField {
columnName: "foo",
show: false,
}
}
}
Now, I would make the helper to auto-generate the table columns and values ​​of a collection field where the show check is true, without having to manually specify {{code}}, {{description}} and so on, pseudo example:
{{ #each CollectionData }}
<thead>
<tr>
{{print each column where show check is == true, without manually specifing any name}}
</tr>
</thead>
<tbody>
<Tr class="object-row">
{{print the value of the column, for this record, where show check is == true, without specifing its name}}
</tr>
</tbody>
...
{{/each}}
Is there any way to do that?
The simpliest way would be to create a template for each TD, something like
<thead>
<tr>
{{#each fetchColumnHeaders}}
{{> columnHeader }}
{{/each}}
</tr>
</thead>
{{ #each CollectionData }}
<tbody>
<Tr class="object-row">
{{#each fetchColumnItems}}
{{> columnItem}}
{{/each}}
</tr>
</tbody>
{{/each}}
<template name="columnHeader">
<th>{{label}}</th>
</template>
<template name="columnItem">
<td>{{label}}</td>
</template>
And then you can write template helpers to return the column headers, and the various items based on your schema

Resources