how to fix column width in IE, chrome for datatables - datatables

I have a table in datatables. problem is some columns have a lot of text squeezed into a small column. it does not seem to readjust the width. Issue here is the table is wider than the container it is within so i do not want to give it a fixed width. i want it to by dynamically adjustable but not squeeze large text into small columns.
The column is remarks
https://jsfiddle.net/shorif2000/aa9wnhd6/
var datax = [{"ID":"10837","COMMS_MATRIX_ID":"729","FILENAME":"INC000023081620-Stage_Universal_Communication_Matrix1.xlsx","CMLINE":"22","SRC":"x.x.x.x","SRC_NET":"x.x.x.x\/25","SRC_ZONE":"s.v.l","SRC_SECZONE":"s","SRC_NETZONE":"v","SRC_LOCZONE":"l","DST":"x.x.x.x","DST_NET":"x.x.x.x\/27","DST_ZONE":"s.v.l","DST_SECZONE":"s","DST_NETZONE":"v","DST_LOCZONE":"l","SPA":"Deny","SPN":"Flow is denied by the security zoning policy","RPA":"Permit","RPN":"Flow is permitted within the same routing domain","FPA":"Permit","FPN":"Flow is permitted using an acceptable port","STATUS":"To implement","PROTOCOL":"TCP","PORTS":"80","NAT_DIR":null,"NAT_IP":null,"ENVIRONMENT":"none","SERVICE_GROUPING":null,"TRACK":"1.5","REMARKS":"EXTERNAL REVERSE PROXY 1 TO MID-TIER LOAD BALANCER","DROW":"9","SRC_DESC":"001","DST_DESC":null,"REMEDY_INC":null,"CREATED_BY":"UddinS2","UPDATED_BY":"UddinS2","SRC_SOCT1":"x","SRC_SOCT2":"232","SRC_SOCT3":"163","SRC_SOCT4":"4","SRC_EOCT1":"x","SRC_EOCT2":"232","SRC_EOCT3":"163","SRC_EOCT4":"4","SRC_CIDR":"32","SRC_NET_SOCT1":"x","SRC_NET_SOCT2":"232","SRC_NET_SOCT3":"163","SRC_NET_SOCT4":"0","SRC_NET_EOCT1":"x","SRC_NET_EOCT2":"232","SRC_NET_EOCT3":"163","SRC_NET_EOCT4":"127","SRC_NET_CIDR":"25","DST_SOCT1":"139","DST_SOCT2":"47","DST_SOCT3":"171","DST_SOCT4":"29","DST_EOCT1":"139","DST_EOCT2":"47","DST_EOCT3":"171","DST_EOCT4":"29","DST_CIDR":"32","DST_NET_SOCT1":"139","DST_NET_SOCT2":"47","DST_NET_SOCT3":"171","DST_NET_SOCT4":"0","DST_NET_EOCT1":"139","DST_NET_EOCT2":"47","DST_NET_EOCT3":"171","DST_NET_EOCT4":"31","DST_NET_CIDR":"27","NAT_TO":null,"NAT_TO_SOCT1":null,"NAT_TO_SOCT2":null,"NAT_TO_SOCT3":null,"NAT_TO_SOCT4":null,"NAT_TO_EOCT1":null,"NAT_TO_EOCT2":null,"NAT_TO_EOCT3":null,"NAT_TO_EOCT4":null,"NAT_FROM":null,"NAT_FROM_SOCT1":null,"NAT_FROM_SOCT2":null,"NAT_FROM_SOCT3":null,"NAT_FROM_SOCT4":null,"NAT_FROM_EOCT1":null,"NAT_FROM_EOCT2":null,"NAT_FROM_EOCT3":null,"NAT_FROM_EOCT4":null,"ECT":"None","DUPLICATES":null,"CMIDS":null,"TS_CREATED":"14-Dec-17 11:04:20"},{"ID":"10838","COMMS_MATRIX_ID":"729","FILENAME":"INC000023081620-Stage_Universal_Communication_Matrix1.xlsx","CMLINE":"23","SRC":"x.x.x.x","SRC_NET":"x.x.x.x\/25","SRC_ZONE":"s.v.l","SRC_SECZONE":"C2","SRC_NETZONE":"VOD","SRC_LOCZONE":"RAT","DST":"x.x.x.x","DST_NET":"139.47.171.0\/27","DST_ZONE":"s.v.l","DST_SECZONE":"TP","DST_NETZONE":"VOD","DST_LOCZONE":"RAT","SPA":"Deny","SPN":"Flow is denied by the security zoning policy","RPA":"Permit","RPN":"Flow is permitted within the same routing domain","FPA":"Permit","FPN":"Flow is permitted using an acceptable port","STATUS":"To implement","PROTOCOL":"TCP","PORTS":"80","NAT_DIR":null,"NAT_IP":null,"ENVIRONMENT":"none","SERVICE_GROUPING":null,"TRACK":"1.5","REMARKS":"EXTERNAL REVERSE PROXY 2 TO MID-TIER LOAD BALANCER","DROW":"9","SRC_DESC":"008","DST_DESC":null,"REMEDY_INC":null,"CREATED_BY":"UddinS2","UPDATED_BY":"UddinS2","SRC_SOCT1":"195","SRC_SOCT2":"232","SRC_SOCT3":"163","SRC_SOCT4":"11","SRC_EOCT1":"195","SRC_EOCT2":"232","SRC_EOCT3":"163","SRC_EOCT4":"11","SRC_CIDR":"32","SRC_NET_SOCT1":"195","SRC_NET_SOCT2":"232","SRC_NET_SOCT3":"163","SRC_NET_SOCT4":"0","SRC_NET_EOCT1":"195","SRC_NET_EOCT2":"232","SRC_NET_EOCT3":"163","SRC_NET_EOCT4":"127","SRC_NET_CIDR":"25","DST_SOCT1":"139","DST_SOCT2":"47","DST_SOCT3":"171","DST_SOCT4":"29","DST_EOCT1":"139","DST_EOCT2":"47","DST_EOCT3":"171","DST_EOCT4":"29","DST_CIDR":"32","DST_NET_SOCT1":"139","DST_NET_SOCT2":"47","DST_NET_SOCT3":"171","DST_NET_SOCT4":"0","DST_NET_EOCT1":"139","DST_NET_EOCT2":"47","DST_NET_EOCT3":"171","DST_NET_EOCT4":"31","DST_NET_CIDR":"27","NAT_TO":null,"NAT_TO_SOCT1":null,"NAT_TO_SOCT2":null,"NAT_TO_SOCT3":null,"NAT_TO_SOCT4":null,"NAT_TO_EOCT1":null,"NAT_TO_EOCT2":null,"NAT_TO_EOCT3":null,"NAT_TO_EOCT4":null,"NAT_FROM":null,"NAT_FROM_SOCT1":null,"NAT_FROM_SOCT2":null,"NAT_FROM_SOCT3":null,"NAT_FROM_SOCT4":null,"NAT_FROM_EOCT1":null,"NAT_FROM_EOCT2":null,"NAT_FROM_EOCT3":null,"NAT_FROM_EOCT4":null,"ECT":"None","DUPLICATES":null,"CMIDS":null,"TS_CREATED":"14-Dec-17 11:04:20"},{"ID":"10839","COMMS_MATRIX_ID":"729","FILENAME":"INC000023081620-Stage_Universal_Communication_Matrix1.xlsx","CMLINE":"24","SRC":"x.x.x.x","SRC_NET":"x.x.x.x\/25","SRC_ZONE":"s.v.l","SRC_SECZONE":"s","v":"l","SRC_LOCZONE":"s","DST":"x.x.x.x","DST_NET":"x.x.x.0\/27","DST_ZONE":"s.v.l","DST_SECZONE":"TP","DST_NETZONE":"VOD","DST_LOCZONE":"RAT","SPA":"Deny","SPN":"Flow is denied by the security zoning policy","RPA":"Permit","RPN":"Flow is permitted within the same routing domain","FPA":"Permit","FPN":"Flow is permitted using an acceptable port","STATUS":"To implement","PROTOCOL":"TCP","PORTS":"80","NAT_DIR":null,"NAT_IP":null,"ENVIRONMENT":"none","SERVICE_GROUPING":null,"TRACK":"1.5","REMARKS":"INTERNAL REVERSE PROXY 1 TO MID-TIER LOAD BALANCER","DROW":"9","SRC_DESC":"-209-207","DST_DESC":null,"REMEDY_INC":null,"CREATED_BY":"UddinS2","UPDATED_BY":"UddinS2","SRC_SOCT1":"195","SRC_SOCT2":"233","SRC_SOCT3":"209","SRC_SOCT4":"207","SRC_EOCT1":"195","SRC_EOCT2":"233","SRC_EOCT3":"209","SRC_EOCT4":"207","SRC_CIDR":"32","SRC_NET_SOCT1":"195","SRC_NET_SOCT2":"233","SRC_NET_SOCT3":"209","SRC_NET_SOCT4":"128","SRC_NET_EOCT1":"195","SRC_NET_EOCT2":"233","SRC_NET_EOCT3":"209","SRC_NET_EOCT4":"255","SRC_NET_CIDR":"25","DST_SOCT1":"139","DST_SOCT2":"47","DST_SOCT3":"171","DST_SOCT4":"29","DST_EOCT1":"139","DST_EOCT2":"47","DST_EOCT3":"171","DST_EOCT4":"29","DST_CIDR":"32","DST_NET_SOCT1":"139","DST_NET_SOCT2":"47","DST_NET_SOCT3":"171","DST_NET_SOCT4":"0","DST_NET_EOCT1":"139","DST_NET_EOCT2":"47","DST_NET_EOCT3":"171","DST_NET_EOCT4":"31","DST_NET_CIDR":"27","NAT_TO":null,"NAT_TO_SOCT1":null,"NAT_TO_SOCT2":null,"NAT_TO_SOCT3":null,"NAT_TO_SOCT4":null,"NAT_TO_EOCT1":null,"NAT_TO_EOCT2":null,"NAT_TO_EOCT3":null,"NAT_TO_EOCT4":null,"NAT_FROM":null,"NAT_FROM_SOCT1":null,"NAT_FROM_SOCT2":null,"NAT_FROM_SOCT3":null,"NAT_FROM_SOCT4":null,"NAT_FROM_EOCT1":null,"NAT_FROM_EOCT2":null,"NAT_FROM_EOCT3":null,"NAT_FROM_EOCT4":null,"ECT":"None","DUPLICATES":null,"CMIDS":null,"TS_CREATED":"14-Dec-17 11:04:20"},{"ID":"10840","COMMS_MATRIX_ID":"729","FILENAME":"INC000023081620-Stage_Universal_Communication_Matrix1.xlsx","CMLINE":"25","SRC":"x.x.x.x","SRC_NET":"x.x.x.x\/25","SRC_ZONE":"s.v.l","SRC_SECZONE":"E1","SRC_NETZONE":"VOD","SRC_LOCZONE":"RAT","DST":"x.x.x.x","DST_NET":"139.47.171.0\/27","DST_ZONE":"s.v.l","DST_SECZONE":"TP","DST_NETZONE":"VOD","DST_LOCZONE":"RAT","SPA":"Deny","SPN":"Flow is denied by the security zoning policy","RPA":"Permit","RPN":"Flow is permitted within the same routing domain","FPA":"Permit","FPN":"Flow is permitted using an acceptable port","STATUS":"To implement","PROTOCOL":"TCP","PORTS":"80","NAT_DIR":null,"NAT_IP":null,"ENVIRONMENT":"none","SERVICE_GROUPING":null,"TRACK":"1.5","REMARKS":"INTERNAL REVERSE PROXY 2 TO MID-TIER LOAD BALANCER","DROW":"9","SRC_DESC":"-209-208","DST_DESC":null,"REMEDY_INC":null,"CREATED_BY":"UddinS2","UPDATED_BY":"UddinS2","SRC_SOCT1":"195","SRC_SOCT2":"233","SRC_SOCT3":"209","SRC_SOCT4":"208","SRC_EOCT1":"195","SRC_EOCT2":"233","SRC_EOCT3":"209","SRC_EOCT4":"208","SRC_CIDR":"32","SRC_NET_SOCT1":"195","SRC_NET_SOCT2":"233","SRC_NET_SOCT3":"209","SRC_NET_SOCT4":"128","SRC_NET_EOCT1":"195","SRC_NET_EOCT2":"233","SRC_NET_EOCT3":"209","SRC_NET_EOCT4":"255","SRC_NET_CIDR":"25","DST_SOCT1":"139","DST_SOCT2":"47","DST_SOCT3":"171","DST_SOCT4":"29","DST_EOCT1":"139","DST_EOCT2":"47","DST_EOCT3":"171","DST_EOCT4":"29","DST_CIDR":"32","DST_NET_SOCT1":"139","DST_NET_SOCT2":"47","DST_NET_SOCT3":"171","DST_NET_SOCT4":"0","DST_NET_EOCT1":"139","DST_NET_EOCT2":"47","DST_NET_EOCT3":"171","DST_NET_EOCT4":"31","DST_NET_CIDR":"27","NAT_TO":null,"NAT_TO_SOCT1":null,"NAT_TO_SOCT2":null,"NAT_TO_SOCT3":null,"NAT_TO_SOCT4":null,"NAT_TO_EOCT1":null,"NAT_TO_EOCT2":null,"NAT_TO_EOCT3":null,"NAT_TO_EOCT4":null,"NAT_FROM":null,"NAT_FROM_SOCT1":null,"NAT_FROM_SOCT2":null,"NAT_FROM_SOCT3":null,"NAT_FROM_SOCT4":null,"NAT_FROM_EOCT1":null,"NAT_FROM_EOCT2":null,"NAT_FROM_EOCT3":null,"NAT_FROM_EOCT4":null,"ECT":"None","DUPLICATES":null,"CMIDS":null,"TS_CREATED":"14-Dec-17 11:04:20"}];
var buttons = {
text: 'Download',
className: 'btn btn-primary dropdown-toggle',
action: function ( e, dt, node, config ) {
}
};
var routing_analysis = false;
var servicedesign = false;
var techops = false;
var statuses = ['To implement','In progress','Implemented', 'To remove'];
var ccpProjectUser = false;
var frozen = false;
$(document).ready( function () {
var table = $('#dt-comms_matrix').DataTable({
dom: "<'row'<'col-md-6'l><'col-md-6'Bf>>" +
"<'row'<'col-md-6'><'col-md-6'>>" +
"<'row'<'col-md-12't>><'row'<'col-md-6'i><'col-md-6'p>>",
"bAutoWidth": false,
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]],
"iDisplayLength": 25,
"processing": true,
"language": {
"loadingRecords": '<i class="fa fa-spinner fa-spin" aria-hidden="true"></i> Loading...',
"processing": '<i class="fa fa-spinner fa-spin" aria-hidden="true"></i> Processing...'
},
stateSave: true,
"order": [[ 2, "asc" ],[1,'asc']],
data: datax,
buttons: [
buttons,
'colvis'
],
"autoWidth": false,
"columnDefs": [
{
targets: [0,3],
"searchable": false,
"sortable": false
},
{
"targets": [ 4 ],
"searchable": false,
"sortable": false
},
{
"targets": [ 18 ],
"width": '100px'
},
],
"columns": [
{
"data": function(row,type,val,meta){
var error = false;
var html = '<div style="width:85px">';
html += '<input type="checkbox" name="select_download['+row.ID+']" data-value="'+row.ID+'" autocomplete="off" data-toggle="popover" data-content="Select to add flow to download" data-trigger="hover" />';
if(ccpProjectUser && !frozen){
html += '<span data-toggle="modal" data-target="#myModalForm" title="Click to edit row" data-row="'+meta.row+'" data-cmid="'+row.COMMS_MATRIX_ID+'" data-id="'+row.ID+'" data-src="'+row.SRC+'" data-src_desc="'+row.SRC_DESC+'" data-dst="'+row.DST+'" data-dst_desc="'+row.DST_DESC+'" data-protocol="'+row.PROTOCOL+'" data-ports="'+row.PORTS+'" data-environment="'+row.ENVIRONMENT+'" data-service_grouping="'+row.SERVICE_GROUPING+'" data-track="'+row.TRACK+'" data-remarks="'+row.REMARKS+'">';
html += '<a class="btn btn-sm btn-info" data-toggle="popover" data-content="Click to edit row" data-trigger="hover" href="javascript:void(0)"><i class="fa fa-pencil" aria-hidden="true"></i></a>';
html += '</span>';
html += '<a class="btn btn-sm btn-danger delete_comms_matrix_flow" data-toggle="popover" data-content="Delete flow" data-trigger="hover" href="javascript:void(0)" data-id="'+row.ID+'"><i class="fa fa-trash" aria-hidden="true"></i></a>';
}
if(error){
return html + '</div>';
}else{
html += '<button type="button" class="btn btn-sm btn-default btn_commsmatrix_ect" data-toggle="popover" data-trigger="hover" data-content="Queue for testing" style="color:#333" href="#" data-cmid="'+row.COMMS_MATRIX_ID+'" data-id="'+row.ID+'" data-src="'+row.SRC+'" data-dst="'+row.DST+'" data-protocol="'+row.PROTOCOL+'" data-ports="'+row.PORTS+'" data-spa="'+row.SPA+'" data-rpa="'+row.RPA+'" data-fpa="'+row.FPA+'"><i class="fa fa-cog" aria-hidden="true"></i></</button>';
}
html += '</div>';
return html;
},
},
{
"data": function(row,type,val,meta){
var dupes = '';
var content = '';
if(parseInt(row.DUPLICATES) > 0){
var cmids = row.CMIDS.split(", ");
for(var i=0;i<cmids.length;i++){
content += "<a href='"+window.location.protocol + "//" + window.location.host + "/api/user/commsmatrix/id/"+cmids[i]+"/format/xml" +"' target='_blank'>"+cmids[i]+"</a> ";
}
dupes = '<span data-toggle="popover" data-placement="top" data-title="duplicate flows" data-content="'+content+'" style="text-decoration:underline"><i class="fa fa-info-circle" aria-hidden="true"></i></span>';
}
if(routing_analysis){
var html = '<a target="_blank" href="/routing_analysis.php?src='+row.SRC+'&dst='+row.DST+'&proto='+row.PROTOCOL+'&port='+row.PORTS+'" data-toggle="popover" data-trigger="hover" data-content="Click to show routing analysis">'+row.ID+'</a>';
if(parseInt(row.DUPLICATES) > 0){
html += dupes;
}
return html;
}else{
if(parseInt(row.DUPLICATES) > 0){
return row.ID + dupes;
}
return row.ID;
}
}
},
{ "data": "CMLINE" },
{
"data": function(row,type,val,meta){
if(techops){
var html = '<div class="form-group">';
html += '<input type="checkbox" name="status[]" value="'+row.ID+'" class="form-control hidden-print">';
html += '<select id="'+row.ID+'_select" name="'+row.ID+'_select" class="status_option form-control">';
var selected = '';
for(i in statuses){
if(row.STATUS == statuses[i]){
selected = 'selected';
}
html += '<option value="'+statuses[i]+'" '+selected+'>'+statuses[i]+'</option>';
selected = '';
}
html += '</select></div>';
return html;
}else{
return row.STATUS;
}
}
},
{
"data": function(row,type,val,meta){
if(techops){
var inc = row.REMEDY_INC;
if(row.REMEDY_INC == null){
inc = '';
}
var html = '<input type="text" name="inc_'+row.ID+'" id="'+row.ID+'_inc" value="'+inc+'" maxlength="15" size="15" class="form-control" />';
return html;
}else{
return '';
}
}
},
{ "data": "SRC" },
{ "data": "SRC_DESC" },
{ "data": "SRC_ZONE" },
{ "data": "DST" },
{ "data": "DST_DESC" },
{ "data": "DST_ZONE" },
{ "data": "PROTOCOL" },
{ "data": "PORTS" },
{ "data": "NAT_DIR" },
{ "data": "NAT_IP" },
{ "data": "ENVIRONMENT" },
{ "data": "SERVICE_GROUPING" },
{ "data": "TRACK" },
{ "data": "REMARKS" },
{ "data": function(row,type,val,meta){
var html = '<span data-toggle="popover" data-trigger="hover" data-container="#dt-comms_matrix" data-content="<span style=\'color:black\'>'+row.SPN+'</span>">'+row.SPA+'</span>';
return html;
}
},
{ "data": "SPN" },
{ "data": function(row,type,val,meta){
var html = '<span data-toggle="popover" data-trigger="hover" data-container="#dt-comms_matrix" data-content="<span style=\'color:black\'>'+row.RPN+'</span>">'+row.RPA+'</span>';
return html;
}
},
{ "data": "RPN" },
{ "data": function(row,type,val,meta){
var html = '<span data-toggle="popover" data-trigger="hover" data-container="#dt-comms_matrix" data-content="<span style=\'color:black\'>'+row.FPN+'</span>">'+row.FPA+'</span>';
return html;
}
},
{ "data": "FPN" },
{
"data": function(row,type,val,meta){
var html = row.ECT;
if(row.ECT != 'None'){
html = ''+row.ECT+'';
}
return html;
}
},
],
});
} );

You will only be able to solve that with hardcoded CSS :
table#dt-comms_matrix thead tr:nth-child(2) th:nth-child(19) {
width: 400px;
min-width: 400px;
}
updated fiddle -> https://jsfiddle.net/aa9wnhd6/4/
table#dt-comms_matrix target the table
thead tr:nth-child(2) target the second header row
th:nth-child(19) target the 19th column
Alternatively set a class on the header element <th class="remarks"> and
table#dt-comms_matrix thead tr:nth-child(2) th.remarks { .. }
https://jsfiddle.net/aa9wnhd6/6/

Related

Why data returning from Laravel 9 api endpoint not showing in Vue UI?

I'm developing simple TodoList app using Laravle 9, VueJS 3, Vite bundler - all this built in tools
when creating Laravel fresh installation.
In app user can make CRUD operations with TodoItem and all user data saved on server, so
data preserved on page refresh.
Application almost finished, unless some strange bug: when I run app on local machine - all works perfectly, but when I deploy it on Heroku and open in browser - I see no todos in UI, although during installation some example todo rows already seeded in db.
I examined API - it returns data as expected:
[
{
"id": 67,
"text": "Thing1",
"is_done": false,
"is_urgent": false,
"created_at": "2022-08-24T09:16:37.000000Z",
"updated_at": "2022-08-24T09:16:37.000000Z"
},
{
"id": 68,
"text": "Buy milk",
"is_done": false,
"is_urgent": false,
"created_at": "2022-08-24T09:16:37.000000Z",
"updated_at": "2022-08-24T09:16:37.000000Z"
},
{
"id": 69,
"text": "Thing2",
"is_done": true,
"is_urgent": false,
"created_at": "2022-08-24T09:16:37.000000Z",
"updated_at": "2022-08-24T09:16:37.000000Z"
},
{
"id": 70,
"text": "Thing3",
"is_done": true,
"is_urgent": false,
"created_at": "2022-08-24T09:16:37.000000Z",
"updated_at": "2022-08-24T09:16:37.000000Z"
}
]
When I create new Todo in textbox request sends to server, and data saved on remote server - but on page refresh - I again get empty data in UI, althout i see in that data loaded
This is my App.vue
<template>
<div class="container mt-5" style="padding-left: 0 !important;">
<h3><span class="fw-bold text-warning">Simple</span> TodoList</h3>
</div>
<div class="container mt-4">
<div class="row">
<!-- Simple todos -->
<div class="col-md-6 py-3" style="border: 1px solid #ddd">
<p>Todos ({{ simpleTodos.length }})</p>
<ul>
<li :id="todo.id"
:key="todo.id"
:class="{ 'text-decoration-line-through': todo['is_done'], 'todo-item__link': true }"
v-for="todo in simpleTodos"
#click="contentVisible === todo.id ? contentVisible = false : contentVisible = todo.id">
{{ todo.text }}
</li>
</ul>
<input type="text" name="todo" id="todo.new" #keydown.enter="addTodo" placeholder="Type todo and press Enter" />
</div>
<!-- Urgent todos -->
<div class="col-md-6 py-3" style="border: 1px solid #ddd">
<p>Todos <span :class="{ 'text-danger': urgentTodos.length >= 3}">({{ urgentTodos.length }})</span></p>
<ul>
<li :id="todo.id"
:key="todo.id"
:class="{ 'text-decoration-line-through': todo['is_done'], 'todo-item__link': true }"
v-for="todo in urgentTodos"
#click="contentVisible === todo.id ? contentVisible = false : contentVisible = todo.id">
{{ todo.text }}
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
import {getAllTodos, createTodo, removeTodo, toggleTodoCompleteStatus, toggleTodoUrgentStatus} from '../services/TodoService'
export default {
name: "App",
data() {
return {
allTodos: [],
contentVisible: false
}
},
mounted() {
this.getAllTodos();
},
computed: {
simpleTodos() {
return this.allTodos.filter(todo => todo['is_urgent'] === 0);
},
urgentTodos() {
return this.allTodos.filter(todo => todo['is_urgent'] === 1);
}
},
methods: {
getAllTodos()
{
getAllTodos()
.then(todos => {
console.log(todos)
this.allTodos = todos
})
.catch(err => {
alert('Error happened while fetching todos!');
console.error(err)
});
},
addTodo(e)
{
// return if value is empty
if(e.target.value.trim().length === 0)
return false;
const clientTodo = { text: e.target.value, is_done: 0, is_urgent: 0 }
createTodo(clientTodo).then(({ todo }) => {
this.allTodos.push(todo);
e.target.value = "";
});
},
}
}
</script>
<style scoped>
.todo-item__link {
cursor: pointer;
position: relative;
}
.todo-item__link .text-primary {
position: absolute;
padding-left: 10px;
}
.todo-item__link:hover {
text-decoration: underline;
}
</style>
I tring to use Vue Debug Tools - it shows empty allTodos list.
I don't unsderstand why this.getAllTodos() doesn't update state on mount
The problem is the is_done and is_urgent properties are Booleans in your API resonse, but your component is incorrectly comparing them to 0 and 1:
export default {
computed: {
simpleTodos() {
//return this.allTodos.filter(todo => todo['is_urgent'] === 0); ❌ Boolean is never a number
return this.allTodos.filter(todo => todo['is_urgent'] === false); ✅
// or
return this.allTodos.filter(todo => !todo.is_urgent); ✅
},
urgentTodos() {
//return this.allTodos.filter(todo => todo['is_urgent'] === 1); ❌ Boolean is never a number
return this.allTodos.filter(todo => todo['is_urgent'] === true); ✅
// or
return this.allTodos.filter(todo => todo.is_urgent); ✅
}
},
methods: {
addTodo(e) {
// const clientTodo = { text: e.target.value, is_done: 0, is_urgent: 0 } ❌ is_done and is_urgent should be Boolean
const clientTodo = { text: e.target.value, is_done: false, is_urgent: false } ✅
}
}
}
demo

Vue 3 Accessing Array Object

I'm trying to generate passwords by reactively. I have an array object inside my instance and I can list this object with v-for. Also and I can generate random passwords with characters in a passArry. But I need to send chars in data to the passArray when the checkbox is checked. But I can't reach options.status What should I do?
<div class="form-check" v-for="options in options" :key="options.optionName">
<input type="checkbox" class="form-check-input" v-model="options.status">
export default {
data() {
return {
generate: 5,
result: '',
passArry : [],
options :[
{
optionName : 'Lowercase',
status : true,
chars : 'abcdefghijklmnopqrstuvwxyz',
},
{
optionName: 'Uppercase',
status: false,
chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
},
{
optionName: 'Numbers',
status: true,
chars: '1234567890',
},
{
optionName: 'Symbols',
status: false,
chars: '~!##$%^&*()_-+={[}]|:;<,>.?/'
},
]
}
},
watch:{
generate(){
this.result.length > 0 ? this.result = '' : this.result
let charLength = this.passArry.length;
for(let i = 0; i < this.generate; i++){
this.result += this.passArry[Math.floor(Math.random() * charLength )]
}
},
In you case you would reach it not with option.status but options[0].status. Note that it is options[Array{Object, Object, Object, Object }], so you need to point at the first element of your array.
You have an 's' too many:
options in options should be option in options and then using this singular option:
<div class="form-check" v-for="option in options" :key="option.optionName">
<input type="checkbox" class="form-check-input" v-model="option.status">
</div>

How to render component data after page load on click

I am using vue js with laravel. I want to reload my data according to date on click.
My data from api is get according to date but in front it is not change
Here is under my app.js code
var socket = new Vue({
el: "#enrollment-app",
components: {
barChart
},
data: {
privateChannleData: null,
exam_type: null,
exam_id: null,
response_exam_data: [],
response_lap_data: [],
response_btn_list: [],
student_list: [],
lineChartData: {
lables: [],
options: [],
dataset: []
}
},
created() {
if (document.getElementById("exam_type"))
this.exam_type = document.getElementById("exam_type").value;
if (document.getElementById("exam_id"))
this.exam_id = document.getElementById("exam_id").value;
if (this.exam_type != null && this.exam_id != null)
this.getEnrollmentStatus();
},
methods: {
getEnrollmentStatus: function(date="null") {
var self = this;
var data_set = [];
var params = {
exam_type: document.getElementById("exam_type").value,
exam_id: document.getElementById("exam_id").value,
date:date,
};
console.log(params);
axios
.post("/api/get_enrollment_data", params)
.then(function(response) {
self.response_exam_data = response.data.data;
//console.log(self.response_exam_data.students[0]);
self.response_exam_data.students[0].forEach(function(ii, vv) {
self.student_list.push(ii);
});
self.response_btn_list=self.response_exam_data.articles[0];
self.lineChartData.dataset = {
labels: [
"Total Enrollment",
"Not Submitted",
"Submitted",
"Total Pass",
"Total Fail"
],
datasets: [
{
label: "Enrollment Data",
backgroundColor: "#f87979",
data: [
parseInt(self.response_exam_data.total_enrollment),
parseInt(self.response_exam_data.not_submitted),
parseInt(self.response_exam_data.submitted_count),
parseInt(self.response_exam_data.total_pass),
parseInt(self.response_exam_data.total_fail)
]
}
]
};
self.lineChartData.options = {
scales: {
yAxes: [
{
ticks: {
beginAtZero: true
}
}
]
},
responsive: true,
maintainAspectRatio: true
};
})
.catch(function(error) {
alert("Error. Try again after sometime.");
});
}
},
});
Here is under my html code.
<div id="enrollment-app">
<button v-for="(button, key) in response_btn_list" type="button" v-on:click="getEnrollmentStatus({{ button }})" class="btn btn-success btn-icon left-icon mr-10" :date="button">lap #{{ key+1 }} </button>
<div class="user-data">
<span class="name block capitalize-font">#{{student.name}}</span>
<span class="time block" style="width:400px;"> Status:- <span class="txt-primary">#{{student.status_text}} </span> Rank:- <span class="txt-primary">#{{student.My_rank}}</span> Time Taken:- <span class="txt-primary">#{{student.timeTaken}}</span><br/>
Result:- <span class="txt-primary">#{{student.final_result}}</span>
Total Marks:- <span class="txt-primary">#{{student.total_marks}}</span>
Obtained Marks:- <span class="txt-primary">#{{student.obtained_marks}}</span>
</span>
<div :class="student.status"></div>
<div class="clearfix"></div>
</div>
</div>
My resultant data on page load
image on laad data
My resultant data after click on button
data after click button
I only want to render data in front end..

Vue component list 2 event handling

Struggling with how to use .sync when you render components from a list. How do I handle the event emitted in my component to update the parent?
Trying to update the categorySet.gradeCategory.predictionWeight in the input.
<category-set v-for="cat in categories" v-bind:key="cat.id" v-bind:category-set="cat"></category-set>
Vue.component('category-set', {
props: ['categorySet'],
template: ' <div class="form-group">\n' +
' <label for="gradeRange" class="col-sm-2 control-label">{{ categorySet.gradeCategory.gradeCategoryName }}</label>\n' +
' <div class="col-sm-1">\n' +
' <input id="gradeRange" class="form-control" type="number" v-bind:value.number="categorySet.gradeCategory.predictionWeight" \n' +
' step="0.5" v-on:input="$emit(\'input\', $event.target.value)" > \n' +
' </div>\n' +
' </div>'
});
Fiddle: https://jsfiddle.net/rhmiller/aq9Laaew/10971/
Personally, I would do it like the following:
The component is passed the array index and the item (cat), with the item you define the item within the component, then bind the input event which then emits the complete object back to the parent with its index, then the parent sets the item back into the data.
As the Final Exam item is nulled the gradeCategory property you need to handle/recover from that as your using it in the view. Also the label is the same in the parent, so prefer to use that else it would be null if you used the gradeCategory one.
Vue.component('categorySet', {
template: '#category-set',
props: ['data', 'index'],
data() {
return {
item: {
label: this.data.label,
showInSummary: this.data.showInSummary,
gradeCategory: Object.assign({
"gradeCategoryName": null,
"groupGradeWeight": 0.0,
"predictionWeight": null,
"id": this.data.id
}, this.data.gradeCategory),
id: this.data.id
}
}
},
methods: {
inputOccurred(e) {
this.$emit('on-change', this.item, this.index)
}
}
});
//
var vm = new Vue({
el: '#app',
data() {
return {
categories: [
{
"label": "Assignments",
"showInSummary": true,
"gradeCategory": {
"gradeCategoryName": "Assignments",
"groupGradeWeight": 0.0,
"predictionWeight": null,
"id": 81
},
"id": 81
}, {
"label": "Reflections",
"showInSummary": true,
"gradeCategory": {
"gradeCategoryName": "Reflections",
"groupGradeWeight": 10.0,
"predictionWeight": null,
"id": 82
},
"id": 82
}, {
"label": "Quizzes",
"showInSummary": true,
"gradeCategory": {
"gradeCategoryName": "Quizzes",
"groupGradeWeight": 10.0,
"predictionWeight": 10.0,
"id": 83
},
"id": 83
}, {
"label": "Attendance \u0026 Participation",
"showInSummary": true,
"gradeCategory": {
"gradeCategoryName": "Attendance \u0026 Participation",
"groupGradeWeight": 0.0,
"predictionWeight": null,
"id": 84
},
"id": 84
}, {
"label": "Final Exam",
"showInSummary": true,
"gradeCategory": null,
"id": 92
}
]
}
},
methods: {
syncCategorie(value, index) {
this.categories[index] = Object.assign(this.categories[index], value);
}
}
});
<div id="app">
<category-set v-for="(cat, index) in categories" :key="cat.id" :data="cat" :index="index" #on-change="syncCategorie"></category-set>
<pre>{{ categories }}</pre>
</div>
<template id="category-set">
<div class="form-group">
<label for="gradeRange" class="col-sm-3 control-label">{{ item.label }}</label>
<div class="col-sm-1">
<input id="gradeRange" class="form-control" type="number" v-model="item.gradeCategory.predictionWeight" step="0.5" #input="inputOccurred">
</div>
</div>
</template>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.14/vue.min.js"></script>
Run the snippet your see it updates the parent fine.
You can just omit the v-on:input part when you add a .sync modifier.
:prop.sync="binding"
will effectively expands into:
:prop="binding" #update:prop="value => binding = value"
( : is just an abbreviation for v-bind: and # for v-on: )

LocalStorage in Vue App with multiple inputs

i dont know if this is possible - but i am working on a Vue app with multiple input fields that posts to the same list - and i need this to be stored somehow, so when you refresh the site, the outputs from the input fields are saved.
This means both the taskList and subTaskList array should be saved ( i know i've only worked on taskList ).
The example i posted here saves the data fine, however if you refresh, it will post all the data in all the components, can this be fixed so it will only be in the right components?
const STORAGE_KEY = 'madplan-storage'
Vue.component('list-component', {
data: function() {
return {
newTask: "",
taskList: [],
newSubTask: "",
subTaskList: [],
};
},
created() {
this.taskList = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
},
template:
'<div>' +
'<section class="prefetch">' +
'<input v-if="showInput" class="input typeahead" type="text" placeholder="Tilføj ret til madplanen" v-model="newTask" v-on:keyup.enter="addTask">' +
'</section>' +
'<details open v-for="task in taskList" v-bind:key="task.text" class="sub-list-item">' +
'<summary>{{ task.text }}<i class="fa fa-times" aria-hidden="true" v-on:click="removeTask(task)"></i>' + '</summary>' +
'<input class="subInput" type="text" placeholder="Tilføj til indøbsseddel" v-model="newSubTask" v-on:keyup.enter="addSubTask">' +
'</details>' +
'</div>',
computed: {
showInput: function() {
return !this.taskList.length
},
},
methods: {
//addTasks
//
addTask: function() {
var task = this.newTask.trim();
if (task) {
this.taskList.push({
text: task
});
this.newTask = "";
localStorage.setItem(STORAGE_KEY, JSON.stringify(this.taskList));
}
},
addSubTask: function() {
var task = this.newSubTask.trim();
if (task) {
this.subTaskList.push({
text: task
});
this.newSubTask = "";
this.$emit('addedtask', task);
localStorage.setItem(STORAGE_KEY, JSON.stringify(this.subTaskList));
}
},
//removeTasks
//
removeTask: function(task) {
var index = this.taskList.indexOf(task);
this.taskList.splice(index, 1);
},
},
});
new Vue({
el: "#madplan",
data: {
newTask: "",
taskList: [],
newSubTask: "",
subTaskList: [],
},
methods: {
acknowledgeAddedTask: function(cls, task) {
this.$data.subTaskList.push({
text: task,
class: "list-item " + cls
})
},
acknowledgeRemovedTask: function(task) {
this.$data.subTaskList = this.$data.subTaskList.filter(it => it.text != task.text)
},
removeSubTask: function(task) {
var index = this.subTaskList.indexOf(task);
this.subTaskList.splice(index, 1);
},
}
});
<section id="madplan" class="section-wrapper">
<section class="check-list">
<div id="mandag" class="dayWrapper">
<h1>Day One</h1>
<list-component
class="mandag"
v-on:addedtask='task => acknowledgeAddedTask("mandag", task)'
></list-component>
</div>
<div id="tirsdag" class="dayWrapper">
<h1>Day Two</h1>
<list-component
class="tirsdag"
v-on:addedtask='task => acknowledgeAddedTask("tirsdag", task)'
></list-component>
</div>
<ul id="indkobsseddel">
<h2>Shopping List</h2>
<li v-for="task in subTaskList" v-bind:key="task.text" :class="task.class">{{ task.text }}<i class="fa fa-times" aria-hidden="true" v-on:click="removeSubTask(task)"></i></li>
</ul>
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js" charset="utf-8"></script>
To be clear, i will come with an example:
As it is now, if i post "Foo" and "Bar" to the "Day One" component and refresh the page, it will then post "Foo" and "Bar" to both "Day One" and "Day Two".
Essentially, i would like to be able to post for an example "Foo" to "Day One", "Bar" to "Day Two" and from there post "Hello World" to the Shopping List, and it would all be saved in the right places, instead of posting everything everywhere.
BTW: I'm a scrub at backend work.
To persist global state, you may use the plugin vue-persistent-state like this:
import persistentStorage from 'vue-persistent-storage';
const initialState = {
newTask: "",
taskList: [],
newSubTask: "",
subTaskList: [],
};
Vue.use(persistentStorage, initialState);
Now newTask, taskList, newSubTask and subTaskList is available as data in all components and Vue instances. Any changes will be stored in localStorage, and you can use this.taskList etc. as you would in a vanilla Vue app.
Your list component now becomes:
Vue.component('list-component', {
// data removed
// created removed
template:
'<div>' +
'<section class="prefetch">' +
'<input v-if="showInput" class="input typeahead" type="text" placeholder="Tilføj ret til madplanen" v-model="newTask" v-on:keyup.enter="addTask">' +
'</section>' +
'<details open v-for="task in taskList" v-bind:key="task.text" class="sub-list-item">' +
'<summary>{{ task.text }}<i class="fa fa-times" aria-hidden="true" v-on:click="removeTask(task)"></i>' + '</summary>' +
'<input class="subInput" type="text" placeholder="Tilføj til indøbsseddel" v-model="newSubTask" v-on:keyup.enter="addSubTask">' +
'</details>' +
'</div>',
computed: {
showInput: function() {
return !this.taskList.length
},
},
methods: {
//addTasks
//
addTask: function() {
var task = this.newTask.trim();
if (task) {
this.taskList.push({
text: task
});
this.newTask = "";
// localStorage.setItem not needed
}
},
addSubTask: function() {
var task = this.newSubTask.trim();
if (task) {
this.subTaskList.push({
text: task
});
this.newSubTask = "";
// $emit not needed, state is global and shared
// localStorage.setItem not needed
}
},
//removeTasks
//
removeTask: function(task) {
var index = this.taskList.indexOf(task);
this.taskList.splice(index, 1);
},
},
});
If you want to understand how this works, the code is pretty simple. It basically
adds a mixin to make initialState available in all Vue instances, and
watches for changes and stores them.
Disclaimer: I'm the author of vue-persistent-state.