Issues with ESP8266 loading files/pictures using SPIFFS-ERR_CONNECTION_RESET - websocket

Alright so I am currently using an ESP8266 HUZZAH to run a webpage using a modified version of the SPIFFS library that is asynchronous: link to library, on a general basis it works great, but every once in a while it will either fail to load a css/js file or one of the images that I'm using on the webpage with the following error:
I need a way to ensure that the css/images will never fail to load if possible. I can't just have the page randomly loading without the styles, that's ridiculous.
Another thing that's been happening is the first load of the page will occur pretty quickly, but then when I refresh, it takes forever for the page to load again.
Here's a list of the files I currently have on the server:
Here's the current version of my code:
Relevant Code from Primary ino File
// WEB HANDLER IMPLEMENTATION (Modified Server Library Code)
class SPIFFSEditor: public AsyncWebHandler {
private:
String _username;
String _password;
bool _uploadAuthenticated;
public:
SPIFFSEditor(String username=String(), String password=String()):_username(username),_password(password),_uploadAuthenticated(false){}
bool canHandle(AsyncWebServerRequest *request){
if(request->method() == HTTP_GET && request->url() == "/edit" && (SPIFFS.exists("/edit.htm") || SPIFFS.exists("/edit.htm.gz")))
return true;
else if(request->method() == HTTP_GET && request->url() == "/list")
return true;
else if(request->method() == HTTP_GET && (request->url().endsWith("/") || SPIFFS.exists(request->url()) || (!request->hasParam("download") && SPIFFS.exists(request->url()+".gz"))))
return true;
else if(request->method() == HTTP_POST && request->url() == "/edit")
return true;
else if(request->method() == HTTP_DELETE && request->url() == "/edit")
return true;
else if(request->method() == HTTP_PUT && request->url() == "/edit")
return true;
return false;
}
//Function used to serve webpage to user (Modified Server Library Code)
void handleRequest(AsyncWebServerRequest *request){
if(_username.length() && (request->method() != HTTP_GET || request->url() == "/edit" || request->url() == "/list") && !request->authenticate(_username.c_str(),_password.c_str()))
return request->requestAuthentication();
if(request->method() == HTTP_GET && request->url() == "/edit"){
request->send(SPIFFS, "/edit.htm");
} else if(request->method() == HTTP_GET && request->url() == "/list"){
if(request->hasParam("dir")){
String path = request->getParam("dir")->value();
Dir dir = SPIFFS.openDir(path);
path = String();
String output = "[";
while(dir.next()){
File entry = dir.openFile("r");
if (output != "[") output += ',';
bool isDir = false;
output += "{\"type\":\"";
output += (isDir)?"dir":"file";
output += "\",\"name\":\"";
output += String(entry.name()).substring(1);
output += "\"}";
entry.close();
}
output += "]";
request->send(200, "text/json", output);
output = String();
}
else
request->send(400);
} else if(request->method() == HTTP_GET){
String path = request->url();
if(path.endsWith("/"))
path += "index.htm";
request->send(SPIFFS, path, String(), request->hasParam("download"));
} else if(request->method() == HTTP_DELETE){
if(request->hasParam("path", true)){
ESP.wdtDisable(); SPIFFS.remove(request->getParam("path", true)->value()); ESP.wdtEnable(10);
request->send(200, "", "DELETE: "+request->getParam("path", true)->value());
} else
request->send(404);
} else if(request->method() == HTTP_POST){
if(request->hasParam("data", true, true) && SPIFFS.exists(request->getParam("data", true, true)->value()))
request->send(200, "", "UPLOADED: "+request->getParam("data", true, true)->value());
else
request->send(500);
} else if(request->method() == HTTP_PUT){
if(request->hasParam("path", true)){
String filename = request->getParam("path", true)->value();
if(SPIFFS.exists(filename)){
request->send(200);
} else {
File f = SPIFFS.open(filename, "w");
if(f){
f.write(0x00);
f.close();
request->send(200, "", "CREATE: "+filename);
} else {
request->send(500);
}
}
} else
request->send(400);
}
}
//Function used to handle uploading web files (Modified Server Library Code)
void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
if(!index){
if(!_username.length() || request->authenticate(_username.c_str(),_password.c_str()))
_uploadAuthenticated = true;
request->_tempFile = SPIFFS.open(filename, "w");
}
if(_uploadAuthenticated && request->_tempFile && len){
ESP.wdtDisable(); request->_tempFile.write(data,len); ESP.wdtEnable(10);
}
if(_uploadAuthenticated && final)
if(request->_tempFile) request->_tempFile.close();
}
};
void setup(){
IPAddress ip(192, 168, 1, 16);
IPAddress subnet(255, 255, 255, 0);
IPAddress gt(192, 168, 1, 1);
//Initialize Serial Connections
initSerial();
//Initialize File System
SPIFFS.begin();
//Initialize WiFi Connection (Modified Server Library Code)
WiFi.mode(WIFI_STA);
//WiFi.config(ip, gt, subnet);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.printf("STA: Failed!\n");
WiFi.disconnect(false);
//Seems to work without this, not sure if necessary
//delay(1000);
WiFi.begin(ssid, password);
}
ArduinoOTA.begin();
//Serial.printf("format start\n"); SPIFFS.format(); Serial.printf("format end\n");
//NEW
ws.onEvent(onEvent);
server.addHandler(&ws);
server.serveStatic("/fs", SPIFFS, "/");
server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", String(ESP.getFreeHeap()));
});
server.addHandler(new SPIFFSEditor(http_username,http_password));
server.onNotFound([](AsyncWebServerRequest *request){
if(mySerial)
{
mySerial.printf("NOT_FOUND: ");
} //end if
if(request->method() == HTTP_GET)
{
if(mySerial)
{
mySerial.printf("GET");
} //end if
} //end if
else if(request->method() == HTTP_POST)
{
if(mySerial)
{
mySerial.printf("POST");
} //end if
} //end else if
else if(request->method() == HTTP_DELETE)
{
if(mySerial)
{
mySerial.printf("DELETE");
} //end if
} //end else if
else if(request->method() == HTTP_PUT)
{
if(mySerial)
{
mySerial.printf("PUT");
} //end if
} //end else if
else if(request->method() == HTTP_PATCH)
{
if(mySerial)
{
mySerial.printf("PATCH");
} //end if
} //end else if
else if(request->method() == HTTP_HEAD)
{
if(mySerial)
{
mySerial.printf("HEAD");
} //end if
} //end else if
else if(request->method() == HTTP_OPTIONS)
{
if(mySerial)
{
mySerial.printf("OPTIONS");
} //end if
} //end else if
else
{
if(mySerial)
{
mySerial.printf("UNKNOWN");
} //end if
} //end else
//Continued Server Initialization (Modified Server Library Code)
if(mySerial)
{
mySerial.printf(" http://%s%s\n", request->host().c_str(), request->url().c_str());
} //end if
if(request->contentLength()){
if(mySerial)
{
mySerial.printf("_CONTENT_TYPE: %s\n", request->contentType().c_str());
mySerial.printf("_CONTENT_LENGTH: %u\n", request->contentLength());
} //end if
} //end if
int headers = request->headers();
int i;
for(i=0;i<headers;i++){
AsyncWebHeader* h = request->getHeader(i);
if(mySerial)
{
mySerial.printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str());
} //end if
}
int params = request->params();
for(i=0;i<params;i++){
AsyncWebParameter* p = request->getParam(i);
if(p->isFile()){
if(mySerial)
{
mySerial.printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size());
} //end if
} else if(p->isPost()){
if(mySerial)
{
mySerial.printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
} //end if
} else {
if(mySerial)
{
mySerial.printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
} //end if
}
}
request->send(404);
});
server.onFileUpload([](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
if(!index)
{
if(mySerial)
{
mySerial.printf("UploadStart: %s\n", filename.c_str());
} //end if
} //end if
if(mySerial)
{
mySerial.printf("%s", (const char*)data);
} //end if
if(final)
{
if(mySerial)
{
mySerial.printf("UploadEnd: %s (%u)\n", filename.c_str(), index+len);
} //end if
} //end if
});
server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
if(!index)
{
if(mySerial)
{
mySerial.printf("BodyStart: %u\n", total);
} //end if
} //end if
if(mySerial)
{
mySerial.printf("%s", (const char*)data);
} //end if
if(index + len == total)
{
if(mySerial)
{
mySerial.printf("BodyEnd: %u\n", total);
} //end if
} //end if
});
server.begin();
//Setup a timer for all WiFi status updates
updateTimerId = timer.setInterval(5000, sendInfoWifi);
}
void loop(){
if(wifiInit == 0)
{
initConnWifi();
} //end if
//Updates whatever timers have been defined
timer.run();
recInfoWifi();
ArduinoOTA.handle();
}
Relevant code from Header ino File
#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <FS.h>
#include <Hash.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <WebSocketsServer.h>
// SKETCH BEGIN
AsyncWebServer server(80);
//NEW
AsyncWebSocket ws("/ws");
//Websocket
WebSocketsServer webSocket = WebSocketsServer(81);
index.html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width initial-scale=1.0">
<title>FITS</title>
<!--CSS-->
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body style='background-color:#4a4a4c;' onload="drawGauges(); startSocket();"> <!--start()-->
<div class="centerPiece">
<h1 class="pageHdr">Fluid Infusion Training System</h1>
<div class="adminLoginButtonDiv">
<a id="adminLoginButton" class="styled-button-11 elementWrapper" onclick="admin_login_init()">Admin Login</a>
<a id="adminLoginCancel" class="styled-button-11RED deactiveSect elementWrapper" onclick="admin_login_cancel()">Cancel Login</a>
<a id="adminLogout" class="styled-button-11RED deactiveSect elementWrapper" onclick="admin_logout()">Admin Logout</a>
</div>
<div id="adminLoginCreds" class="adminLoginCreds deactiveSect">
<div class="elementWrapper">
<label id="adminLoginUserCredLabel" for="adminLoginNameCred">User: </label>
<input type="text" id="adminLoginUserCred">
</div>
<div class="elementWrapper">
<label id="adminLoginPassCredLabel" for="adminLoginPassCred">Password: </label>
<input type="password" id="adminLoginPassCred">
</div>
<div class="elementWrapper">
<a id="adminLoginSubmit" class="submit" onclick="admin_login_submit()">Submit</a>
</div>
</div>
<div style="clear:both;"></div>
<div class='counterContainer'>
<span id="counterText" style="color:white;"></span>
</div>
<div id='adminControls' class='adminControlsRow deactiveSect'>
<h2>Administrator Controls</h2>
<div id='Newbtn' class='powerSwitchContainer'>
<h2>HHIO PTT Power</h2>
<!--HHIO PTT Power Switch-->
<span class="switch">
<span class="switch-border1">
<span class="switch-border2">
<input id="switch1" type="checkbox" onclick='POWERswitch()' checked />
<label for="switch1"></label>
<span class="switch-top"></span>
<span class="switch-shadow"></span>
<span class="switch-handle"></span>
<span class="switch-handle-left"></span>
<span class="switch-handle-right"></span>
<span class="switch-handle-top"></span>
<span class="switch-handle-bottom"></span>
<span class="switch-handle-base"></span>
<span class="switch-led switch-led-green">
<span class="switch-led-border">
<span class="switch-led-light">
<span class="switch-led-glow"></span>
</span>
</span>
</span>
<span class="switch-led switch-led-red">
<span class="switch-led-border">
<span class="switch-led-light">
<span class="switch-led-glow"></span>
</span>
</span>
</span>
</span>
</span>
</span>
</div>
<!--Flushing Button-->
<div class='flushBtnContainer'>
<h2>Fluid Reservoir</h2>
<button id='flushBtn' onmousedown="FLUSHbegin();" onmouseup="FLUSHend();">Flush</button>
</div>
</div>
<div id="mainControls" class="mainControlsRow deactiveSect">
<h2 class="mainHdr">Maintenance Controls</h2>
</div>
<div class="battFluid">
<!--COLUMN HEADERS-->
<div class='headerRow'>
<div class="topHeader">
<h3 class="headerStyle under">Battery</h3>
</div>
<div class="topHeader">
<h3 class="headerStyle under">Marrow</h3>
</div>
</div>
<div id="battery0" class="battery">
<div id="battery100" class="juice"></div>
</div>
<svg width="50px" height="50px" viewBox="0 0 100 150" class="battChgContainer">
<polygon id="battChgContainer" stroke="gray" fill="grey" points="100,0 67,50 90,45 47,100 70,95 0,150 27,110 12,113 50,70 30,73 100,0" />
</svg>
<svg id="battLowContainer" width="120px" height="120px" viewBox="0 0 100 190" class="battLowContainer deactiveSect">
<polygon stroke="gray" fill="#1A1A1C" points="85,151 85,110 100,110 105,105 110,100 115,95 115,50 100,50 100,20 85,20 85,50 65,50 65,20 50,20 50,50 35,50 35,95 40,100 45,105 50,110 65,110 65,151"></polygon>
</svg>
<h1 id="hdr100" class="hdr100">100%</h1>
<!--FLUID GAUGE-->
<table class="fluidGauge">
<tr>
<td>
<div style="width: 140px; height: 225px;" class="fluidReservoir blood">
<div class="tube">
</div>
<div class="liquid">
<div class="head">
</div>
<div id="fluidReservoirHeight" class="body">
<div class="drop large">
</div>
<div class="drop medium">
</div>
<div class="drop small">
</div>
</div>
<div class="tail">
</div>
</div>
<div class="glitter">
</div>
</div>
</td>
</tr>
</table>
</div>
<!--COLUMN HEADERS-->
<div class='headerRow'>
<div class="header">
<h3 class="headerStyle under">Left</h3>
</div>
<div class="header">
<h3 class="headerStyle under">Sternum</h3>
</div>
<div class="header">
<h3 class="headerStyle under">Right</h3>
</div>
</div>
<!--MICROSWITCHES-->
<div class='microswitchRow'>
<div class="microswitchContainer">
<div id="microC" class="microswitch white">
<input type="radio" name="switchC" class="microswitchRadio" id="switchOffC" checked>
<input type="radio" name="switchC" class="microswitchRadio" id="switchOnC">
<label id="switchOffLabelC" for="switchOffC" class="headerStyle">Detached</label>
<label id="switchOnLabelC" for="switchOnC" class="headerStyle deactiveSect">Attached</label>
<span class="toggle"></span>
</div>
</div>
<div class="microswitchContainer">
<div id="microD" class="microswitch white">
<input type="radio" name="switchD" class="microswitchRadio" id="switchOffD" checked>
<input type="radio" name="switchD" class="microswitchRadio" id="switchOnD">
<label id="switchOffLabelD" for="switchOffD" class="headerStyle">Detached</label>
<label id="switchOnLabelD" for="switchOnD" class="headerStyle deactiveSect">Attached</label>
<span class="toggle"></span>
</div>
</div>
<div class="microswitchContainer">
<div id="microE" class="microswitch white">
<input type="radio" name="switchE" class="microswitchRadio" id="switchOffE" checked>
<input type="radio" name="switchE" class="microswitchRadio" id="switchOnE">
<label id="switchOffLabelE" for="switchOffE" class="headerStyle">Detached</label>
<label id="switchOnLabelE" for="switchOnE" class="headerStyle deactiveSect">Attached</label>
<span class="toggle"></span>
</div>
</div>
</div>
<!--VALVES-->
<div class='valveRow'>
<div class='valveContainer'>
<img id="openValveC" src="openvalve.png" alt="open valve C" class="openValvePic">
<img id="closedValveC" src="closedvalve.png" alt="closed valve C" class="deactiveSect closedValvePic">
</div>
<div class='valveContainer'>
<img id="openValveD" src="openvalve.png" alt="open valve D" class="openValvePic deactiveSect">
<img id="closedValveD" src="closedvalve.png" alt="closed valve D" class="closedValvePic">
</div>
<div class='valveContainer'>
<img id="openValveE" src="openvalve.png" alt="open valve E" class="openValvePic">
<img id="closedValveE" src="closedvalve.png" alt="closed valve E" class="deactiveSect closedValvePic">
</div>
</div>
<!--PRESSURE GAUGES-->
<div id="pGauges" class="pressureRow">
<div class="pressureContainer pContainC">
<div id="pGaugeC">
<canvas id="pressureGaugeC" class="gauge"></canvas>
</div>
<div class="pGaugeText">
<div class="bubble">
<div class="num"></div>
<div id="pgcValue" class="rotating">
0.00
</div>
</div>
<span class="psi">PSI</span>
</div>
</div>
<div class="pressureContainer pContainD">
<div id="pGaugeD">
<canvas id="pressureGaugeD" class="gauge"></canvas>
</div>
<div class="pGaugeText">
<div class="bubble">
<div class="num"></div>
<div id="pgdValue" class="rotating">
0.00
</div>
</div>
<span class="psi">PSI</span>
</div>
</div>
<div class="pressureContainer pContainE">
<div id="pGaugeE">
<canvas id="pressureGaugeE" class="gauge"></canvas>
</div>
<div class="pGaugeText">
<div class="bubble">
<div class="num"></div>
<div id="pgeValue" class="rotating">
0.00
</div>
</div>
<span class="psi">PSI</span>
</div>
</div>
</div>
</div>
<!--LED BUTTON-->
<div style='background-color:#1E1E20; clear:both;'>
<h3 class="headerStyle under">LED Controls</h3>
<div id='LEDbtn' class='onoffswitch'>
<input type='checkbox' name='onoffswitch' class='onoffswitch-checkbox' id='myonoffswitch' onclick='LEDswitch()'>
<label class='onoffswitch-label' for='myonoffswitch'>
<span class='onoffswitch-inner'></span>
<span class='onoffswitch-switch'></span>
</label>
</div>
</div>
<script src="general.js"></script>
</body>
</html>

Alright so I think I've solved most, if not all of my issues by updating the libraries, including using the git version of the esp8266 library found here: ESP Link
I also had to update my functions to match the example found in the new libraries.
So thank you everyone for your assistance.

Related

Splice doesn't delete any item from array - Angular12

I am trying create a function for deleting specific items from a shopping cart.
It doesn't give any errors, but when I click the button nothing happens. Any idea what might be the problem?
See the codes below about my issue.
service.ts
removeCartItem(product: Product){
this.cartItemList.map((a:any, index:any)=>{
if(product.id=== a.id){
this.cartItemList.splice(index,1);
}
})
cartitem.component.html
<div class="cartitem">
<div class="container">
<div class="row">
<div class="col">
{{ cartItem.name }}
</div>
<div class="col">
<img [src]="cartItem.imageUrl" class="card-img-top" alt="..." />
</div>
<div class="col-5">
{{ cartItem.description }}
</div>
<div class="col">{{ cartItem.price | currency: "EUR" }}</div>
<div class="col">{{ cartItem.qty }}</div>
<div>
<button (click)="removeItem(item)" class="btn btn-primary">
Remove from cart
</button>
</div>
</div>
</div>
</div>
cartitem.component.ts
constructor(public service: MessengerService) { }
ngOnInit(): void {
}
removeItem(item: Product){
this.service.removeCartItem(item);
}
cart.component.ts
cartItems: Product[] = [];
cartTotal = 0;
product: any;
constructor(private msg: MessengerService, public dialog: MatDialog) {}
ngOnInit() {
this.msg.getMsg().subscribe((product: Product) => {
this.addProductToCart(product);
});
}
addProductToCart(product: Product) {
let productExists = false;
for (let i in this.cartItems) {
if (this.cartItems[i].id === product.id) {
this.cartItems[i].qty++;
productExists = true;
break;
}
}
if (!productExists) {
this.cartItems.push({
id: product.id,
name: product.name,
description: product.description,
qty: 1,
price: product.price,
imageUrl: product.imageUrl,
purchased:product.purchased
});
}
this.cartItems.forEach((item) => {
this.cartTotal += item.qty * item.price;
});
}
cart.component.html
<ul *ngIf="cartItems.length > 0" class="list-group">
<li class="list-group-item">
<h3>My Cart</h3>
</li>
<li class="list-group-item" *ngFor="let item of cartItems">
<app-cartitem [cartItem]="item"></app-cartitem>
</li>
<li class="list-group-item">
<span>Total: {{ cartTotal | currency: "EUR" }} </span>
</li>
<li class="list-group-item">
<button
id="btnFinalize"
class="btn btn-primary"
(click)="purchaseDisabled(product)"
>
Finalize purchase
</button>
</li>
</ul>
The problem is that you are trying to splice inside map. Changing to the following will work:
removeCartItem(product: Product){
let indexToRemove: number = -1;
this.cartItemList.map((a:any, index:any)=>{
if(product.id === a.id){
indexToRemove = index;
}
return a;
});
if(indexToRemove !== -1){
this.cartItemList.splice(indexToRemove,1);
}
}
But notice there is no need to use map here. It's a waste of time and memory to copy the entire array again. Just a loop through the array to find the index to remove would be enough:
removeCartItem(product: Product){
let indexToRemove: number = -1;
let index: number = 0;
for(const cardItem of this.cartItemList){
if(product.id === cardItem.id){
indexToRemove = index;
}
index++;
}
if(indexToRemove !== -1){
this.cartItemList.splice(indexToRemove,1);
}
}

how to upload csv file nuxtjs to API

Nuxt.js I searched lots of tutorials for CSV uploading using laravel API but I did not get logic on how to code csv uploading things help me to solve this or give tutorial links.
Modules
import { AxiosResponse } from "axios";
import { axios } from "#/plugins/axios";
export default {
async importVsim(params: any): Promise<AxiosResponse<null>> {
return await <AxiosResponse>axios.post('v1/ucl/import',params);
}
}
Components
<template>
<div style="display:inline; text-align:left;">
<b-button icon-left="upload" #click="open">UCL CSV</b-button>
<b-modal
v-model="showModal"
trap-focus
aria-role="dialog"
aria-label="Example Modal"
:width="600"
aria-modal>
<div class="card mb-4">
<header class="card-header">
<p class="card-header-title">UCL CSV</p>
</header>
<div class="card-content">
<b-field label="mnk_*.csv">
<b-upload v-model="file1" class="file-label">
<span class="file-cta">
<b-icon class="file-icon" icon="upload"></b-icon>
<span class="file-label">Click to upload</span>
</span>
<span class="file-name" v-if="file1">
{{ file1.name }}
</span>
</b-upload>
</b-field>
<b-field label="htk_*.csv">
<b-upload v-model="file2" class="file-label">
<span class="file-cta">
<b-icon class="file-icon" icon="upload"></b-icon>
<span class="file-label">Click to upload</span>
</span>
<span class="file-name" v-if="file2">
{{ file2.name }}
</span>
</b-upload>
</b-field>
<div style="text-align:center;">
<b-button #click="close" :loading="loading">cancel</b-button>
<b-button class="is-primary" #click="upload" :loading="loading">Ok</b-button>
</div>
</div>
</div>
</b-modal>
</div>
</template>
<script lang="ts">
import { Component, Vue } from "nuxt-property-decorator"
import importCsv from "#/modules/importCsv"
#Component({})
export default class extends Vue {
file1: any = null
file2: any = null
loading: boolean = false
showModal: boolean = false
errors: any = {}
async upload() {
const response = await importCsv.importVsim(this.file2)
console.log(response)
}
open() {
this.errors = {}
this.showModal = true
}
close() {
this.showModal = false
}
}
</script>

Why the images of the publications are altered at the moment that I make a new publication with images?

when I reload browser I can see the post's pics
I have a component referring to the posts, but when you make a post that contains images, they are not updated and the post remains with the images from the previous post, the only way to prevent this from happening is by updating the browser and it should not be like that
Could someone help me to know what is happening, if I should update the component when loading the images or what should I do?
Thanks!
fomPost.vue =>
<template>
<div class="card bg-dark border-left-primary border-right-primary shd mb-4">
<div class="card-body">
<div v-if="status_msg" :class="{ 'alert-green': status, 'alert-danger': !status }" class="alert"
role="alert">{{ status_msg }}
</div>
<div class="form-group">
<textarea id="content-body" class="form-control" v-model="body"></textarea>
<a href="javascript:void(0)" class="text-lg float-right" data-toggle="tooltip"
data-title="Agregar imágenes" data-placement="bottom" #click="toggle()">
<i class="fas fa-cloud-upload-alt"></i>
</a>
</div>
<div v-show="isOpen" :style="'margin-top: 2rem'">
<div class="uploader"
#dragenter="OnDragEnter"
#dragleave="OnDragLeave"
#dragover.prevent
#drop="onDrop"
:class="{ dragging: isDragging }">
<div class="upload-control" v-show="images.length">
<label for="file">Agregar más imágenes</label>
</div>
<div v-show="!images.length">
<p>Arrastra las imágenes ó</p>
<div class="file-input">
<label for="file">Selecciónalas</label>
<input type="file" id="file" #change="onInputChange"
accept="image/x-png,image/gif,image/jpeg" multiple>
</div>
</div>
</div>
<div class="images-preview" v-show="images.length">
<div class="img-wrapper" v-for="(image, index) in images" :key="index">
<div class="thumbnail" :style="`background-image: url(${image.replace(/(\r\n|\n|\r)/gm)})`">
<div class="options">
<div>
<a href="javascript:void(0)" class="text-light" uk-tooltip="title: Eliminar"
#click="removeimage(index)">
<i class="fas fa-trash-alt"></i>
</a>
</div>
<div>
<a href="javascript:void(0)" class="text-light" uk-tooltip="title: Previsualizar"
uk-toggle="target: #modal-media-image" #click="showImage(image)">
<i class="fas fa-search-plus"></i>
</a>
</div>
</div>
</div>
<div class="details">
<span class="size" v-text="getFileSize(files[index].size)"></span>
</div>
<div id="modal-media-image" class="uk-flex-top" uk-modal>
<div class="uk-modal-dialog uk-width-auto uk-margin-auto-vertical">
<button class="uk-modal-close-outside" type="button" uk-close></button>
<img width="1024px" :src="dialogImageUrl">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer bg-opacity-7-dark">
<button type="button" #click="createPost" class="btn btn-primary float-right">
<template v-if="isCreatingPost" class="align-items-center">
<div class="d-flex align-items-center">
<span class="mr-1">Publicando</span>
<div class="loadingio-spinner-dual-ring-botj7pu8xqc">
<div class="ldio-ifliw7yncz">
<div></div>
<div>
<div></div>
</div>
</div>
</div>
</div>
</template>
<template v-else>
Publicar
</template>
</button>
</div>
</div>
</template>
<script>
import {mapActions} from 'vuex'
export default {
name: "FormPostText",
props: ['profile'],
data() {
return {
dialogImageUrl: "",
dialogVisible: false,
isDragging: false,
dragCount: 0,
files: [],
images: [],
status_msg: "",
status: "",
isCreatingPost: false,
title: "",
body: "",
isOpen: false
}
},
mounted() {
$("#content-body").emojioneArea({
placeholder: "¿Qué estás pensando?",
searchPlaceholder: "Buscar",
buttonTitle: "Usa la tecla [TAB] para insertarlos más rápido",
pickerPosition: 'bottom',
filtersPosition: "bottom",
searchPosition: "top"
});
},
methods: {
...mapActions({
create: "post/makePost"
}),
showImage(file) {
this.dialogImageUrl = file;
this.dialogVisible = true;
},
OnDragEnter(e) {
e.preventDefault();
this.dragCount++;
this.isDragging = true;
return false;
},
OnDragLeave(e) {
e.preventDefault();
this.dragCount--;
if (this.dragCount <= 0)
this.isDragging = false;
},
onInputChange(e) {
const files = e.target.files;
Array.from(files).forEach(file => this.addImage(file));
},
onDrop(e) {
e.preventDefault();
e.stopPropagation();
this.isDragging = false;
const files = e.dataTransfer.files;
Array.from(files).forEach(file => this.addImage(file));
},
addImage(file) {
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.showNotification("La imágen no puede ser mayor a 2MB.");
return;
}
if (!file.type.match('image.*')) {
this.showNotification(`${file.name} no es una imágen`);
return;
}
this.files.push(file);
const img = new Image(), reader = new FileReader();
reader.onload = (e) => this.images.push(e.target.result);
reader.readAsDataURL(file);
return isLt2M;
},
removeimage: function (index) {
this.images.splice(index, 1);
},
getFileSize(size) {
const fSExt = ['Bytes', 'KB', 'MB', 'GB'];
let i = 0;
while (size > 900) {
size /= 1024;
i++;
}
return `${(Math.round(size * 100) / 100)} ${fSExt[i]}`;
},
toggle() {
this.isOpen = !this.isOpen;
},
createPost() {
var body = $("#content-body").val();
var text = emojione.toImage(body);
if (!this.validateForm()) {
return false;
}
this.isCreatingPost = true;
const formData = new FormData();
formData.append("user", this.profile.uid);
formData.append("body", text);
this.files.forEach(file => {
formData.append('images[]', file, file.name);
});
this.create(formData).then((res) => {
if (res.data.status === 0) {
this.status = code;
this.showNotification(res.data.msg);
}
document.querySelector(".emojionearea-editor").innerHTML = '';
this.isCreatingPost = false;
this.images = [];
this.files = [];
this.isOpen = false;
let post = res.data;
this.$emit("new", post);
}).catch(error => {
console.log(error)
this.isCreatingPost = false;
});
},
validateForm() {
if (!$("#content-body").val()) {
this.status = false;
this.showNotification("Debes escribir algo para publicar...");
return false;
}
return true;
},
showNotification(message) {
this.$swal.fire({
icon: 'error',
html: message
});
}
}
}
</script>
Post.vue =>
<template>
<div id="timeline">
<div v-if="authenticated.username === username || isFriend">
<FormPost :profile="profile" #new="addPostText"></FormPost>
</div>
<!--<pre>{{postsArr}}</pre>-->
<div v-if="postsCount > 0">
<div v-for="(post, index) in postsArr" :key="index">
<div class="cardbox shadow-lg bg-opacity-5-dark shd">
<div class="cardbox-heading">
<div class="dropdown float-right">
<button class="btn btn-sm btn-dark btn-circle" data-toggle="dropdown"
data-boundary="window">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu dropdown-scale dropdown-menu-right" role="dropdown">
<template v-if="post.user.id === user.uid || post.friend.id === user.uid">
<b-dropdown-item href="javascript:void(0)" #click="deletePost(post.post.id, index)">
<span class="uk-margin-small-right" uk-icon="icon: trash"></span> Eliminar
</b-dropdown-item>
<b-dropdown-divider></b-dropdown-divider>
</template>
<b-dropdown-item href="javascript:void(0)">
<span class="uk-margin-small-right text-danger" uk-icon="icon: warning"></span>
Reportar
</b-dropdown-item>
</div>
</div>
<div class="media m-0">
<div class="d-flex mr-3">
<a v-bind:href="post.user.username">
<img class="img-fluid rounded-circle" v-bind:src="post.friend.photo" alt="User">
</a>
</div>
<div class="media-body">
<p class="m-0"><a v-bind:href="post.friend.username">{{ '#' + post.friend.username }}</a></p>
<small><span><i
class="far fa-clock"></i> {{ since(post.post.created_at) }}</span></small>
</div>
</div>
</div>
<div class="cardbox-item">
<p class="mx-4">{{ post.post.body | setEmoji }}</p>
<div v-if="post.images.length > 0">
<!--<photo-grid
:box-height="'600px'"
:box-width="'100%'"
:boxBorder="0"
:excess-text="'+ {{count}} imágenes'"
uk-lightbox="animation: slide"
>
<img v-for="(imahe, index) in post.images" v-bind:src="`http://127.0.0.1:8000/storage/images/${post.friend.id}/${imahe.url}`" :key="index"/>
</photo-grid>-->
<ImagesGrid :images="post.images" :idFriend="post.friend.id"
uk-lightbox="animation: slide"></ImagesGrid>
</div>
</div>
<div class="cardbox-base">
<ul class="float-right">
<li><a><i class="fa fa-comments"></i></a></li>
<li><a><em class="mr-5">{{ post.comments_count || comments_count }}</em></a></li>
<li><a><i class="fa fa-share-alt"></i></a></li>
<li><a><em class="mr-3">03</em></a></li>
</ul>
<ul>
<li>
<Likes :postid="post.post.id" :user="user"></Likes>
</li>
<li><a href="#"><img
src="http://www.themashabrand.com/templates/bootsnipp/post/assets/img/users/3.jpeg"
class="img-fluid rounded-circle" alt="User"></a></li>
<li><a href="#"><img
src="http://www.themashabrand.com/templates/bootsnipp/post/assets/img/users/1.jpg"
class="img-fluid rounded-circle" alt="User"></a></li>
<li><a href="#"><img
src="http://www.themashabrand.com/templates/bootsnipp/post/assets/img/users/5.jpg"
class="img-fluid rounded-circle" alt="User"></a></li>
<li><a href="#"><img
src="http://www.themashabrand.com/templates/bootsnipp/post/assets/img/users/2.jpg"
class="img-fluid rounded-circle" alt="User"></a></li>
<li><a><span>242 Likes</span></a></li>
</ul>
</div>
<CommentsPost
#new="commentsCount"
:postid="post.post.id"
:postuserid="user.uid"
:user="user"
></CommentsPost>
</div>
</div>
<nav class="pagination-outer">
<ul class="pagination">
<li class="page-item" :class="[pagination.current_page > 1 ? '' : 'disabled']">
<a href="#" class="page-link" aria-label="Previous" #click.prevent="changePage(pagination.current_page - 1)">
<span aria-hidden="true">«</span>
</a>
</li>
<li class="page-item" v-for="page in pagesNumber" :class="[page == isActived ? 'active' : '']">
<a class="page-link" href="#" v-bind:data-hover="page" #click.prevent="changePage(page)">{{page}}</a>
</li>
<li class="page-item" :class="[pagination.current_page < pagination.last_page ? '' : 'disabled']">
<a href="#" class="page-link" aria-label="Next" #click.prevent="changePage(pagination.current_page + 1)">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
<div v-else class="card bg-opacity-5-dark mb-4">
<div class="card-body">
<span class="text-light">No tiene posts aún.</span>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
var moment = require("moment");
moment.locale("es");
import {mapActions, mapGetters} from 'vuex'
import FormPost from "../Posts/FormPost";
import Likes from "../Posts/Likes";
import CommentsPost from "../Posts/CommentsPost";
import ImagesGrid from "../Posts/ImagesGrid";
export default {
name: "Posts",
props: {
username: {
type: String,
required: true
},
profile: {
type: Object,
required: true
},
user: {
type: Object,
required: true
},
isFriend: {
type: Boolean,
required: true
}
},
data() {
return {
page: 0,
offset: 4,
comments_count: ''
}
},
mounted() {
this.getPosts();
},
beforeRouteEnter(to, from, next) {
this.getPosts()
next()
},
beforeRouteUpdate(to, from, next) {
this.getPosts()
next()
},
computed: {
...mapGetters({
authenticated: "auth/authenticated",
postsArr: "post/postsLists",
pagination: "post/postsPagination",
postsCount: "post/postsCount"
}),
isActived: function() {
return this.pagination.current_page;
},
pagesNumber: function () {
if(!this.pagination.to) {
return [];
}
var from = this.pagination.current_page - this.offset;
if(from < 1) {
from = 1;
}
var to = from + (this.offset * 2);
if(to >= this.pagination.last_page) {
to = this.pagination.last_page;
}
var pagesArray = [];
while(from <= to) {
pagesArray.push(from);
from++;
}
return pagesArray;
}
},
methods: {
...mapActions({
getPostsByUser: "post/fetchPosts",
removePost: "post/deletePost",
}),
async getPosts(page) {
await this.getPostsByUser(page);
await this.$forceUpdate();
},
async addPostText(post) {
await this.postsArr.unshift(post);
await this.$forceUpdate();
await this.changePage(1);
},
since(d) {
return moment(d).fromNow();
},
commentsCount(count) {
this.comments_count = count;
},
deletePost(post, index) {
this.postsArr.splice(index, 1)
this.removePost(post)
},
changePage(page) {
this.pagination.current_page = page;
this.getPosts(page);
}
},
filters: {
setEmoji: (value) => {
var rx = /<img\s+(?=(?:[^>]*?\s)?class="[^">]*emojione)(?:[^>]*?\s)?alt="([^"]*)"[^>]*>(?:[^<]*<\/img>)?/gi;
return value.replace(rx, "$1")
}
},
components: {
FormPost,
Likes,
CommentsPost,
ImagesGrid
},
watch: {
'$route': 'getPosts'
}
ImagesGrid.vue =>
<template>
<photo-grid
:box-height="'600px'"
:box-width="'100%'"
:boxBorder="0"
:excess-text="'+ {{count}} imágenes'"
uk-lightbox="animation: slide"
>
<a :href="`http://127.0.0.1:8000/storage/images/${idFriend}/${imahe.url}`"
v-for="(imahe, index) in images"
v-bind:data-image="`http://127.0.0.1:8000/storage/images/${idFriend}/${imahe.url}`"
:key="index">
</a>
</photo-grid>
</template>
<script>
export default {
props: ['idFriend', 'images'],
watch: {
$route(to, from, next) {
this.$forceUpdate();
next()
}
}
};
</script>
Post.js =>
import axios from 'axios'
import store from './index'
export default {
namespaced: true,
state: {
posts: [],
posts_count : 0,
pagination: {
'total': 0,
'current_page': 0,
'per_page': 0,
'last_page': 0,
'from': 0,
'to': 0,
}
},
getters: {
postsLists(state) {
return state.posts;
},
postsCount(state) {
return state.posts_count
},
postsPagination(state) {
return state.pagination
}
},
mutations: {
SET_POST_COLLECTION (state, data) {
state.posts = data.posts.data ;
state.pagination = data.paginate;
state.posts_count = data.paginate.total;
}
},
actions: {
makePost({commit,dispatch}, data) {
return new Promise((resolve, reject) => {
axios.post('user/post/create', data)
.then((response) => {
dispatch("fetchPosts", 1)
resolve(response);
})
.catch((error) => {
reject(error);
});
})
},
fetchPosts({commit}, page) {
return new Promise((resolve, reject) => {
axios.get(`user/${store.state.user.profile.username}/posts?page=${page}`)
.then((response) => {
//console.log(response.data.posts.data);
commit('SET_POST_COLLECTION', response.data);
resolve(response);
})
.catch((error) => {
reject(error);
});
})
},
deletePost({commit}, id) {
return new Promise((resolve, reject) => {
let params = {'id': id};
axios.post('user/post/delete', params)
.then((response) => {
console.log(response.data)
resolve(response);
})
.catch((error) => {
reject(error);
});
})
},
createComment({commit}, comment) {
return new Promise((resolve, reject) => {
axios.post('user/post/comment/create', comment)
.then((response) => {
console.log(response.data)
resolve(response);
})
.catch((error) => {
reject(error);
});
})
}
}
}

VUE.JS template not showing up

I have created a template for chat module. It was working fine yesterday but today there were some issues in some npm module so I ran the command npm audit fix --force and after that command is finished my chat template or any VUE template stops working means it is not showing up.
Here is the code of my template.
<template>
<div>
<div class="row">
<div class="col-md-12">
<div class="panel panel-primary">
<div class="panel-heading">
<span class="glyphicon glyphicon-comment"></span> Chat with {{ withUser.name }}
<button class="btn btn-warning btn-sm pull-right" #click="startVideoCallToUser(withUser.id)" type="button">
<span class="fa fa-video-camera"></span> Video Call
</button>
</div>
<div class="panel-body">
<ul class="chat" v-chat-scroll>
<li class="clearfix" v-for="message in messages" v-bind:class="{ 'right' : check(message.sender.id), 'left' : !check(message.sender.id) }">
<span class="chat-img" v-bind:class="{ 'pull-right' : check(message.sender.id) , 'pull-left' : !check(message.sender.id) }">
<img :src="'http://placehold.it/50/FA6F57/fff&text='+ message.sender.name" alt="User Avatar" class="img-circle" />
</span>
<div class="chat-body clearfix">
<div class="header">
<small class=" text-muted"><span class="glyphicon glyphicon-time"></span><timeago :since="message.created_at" :auto-update="10"></timeago></small>
<strong v-bind:class="{ 'pull-right' : check(message.sender.id) , 'pull-left' : !check(message.sender.id)}" class="primary-font">
{{ message.sender.name }}
</strong>
</div>
<p v-bind:class="{ 'pull-right' : check(message.sender.id) , 'pull-left' : !check(message.sender.id)}">
{{ message.text }}
</p>
<div class="row">
<div class="col-md-3" v-for="file in message.files">
<img :src="file.file_details.webPath" alt="" class="img-responsive">
<a :href="file.file_details.webPath" target="_blank" download>Download - {{ file.name }}</a>
</div>
</div>
</div>
</li>
</ul>
</div>
<div class="panel-footer">
<div class="input-group">
<input id="btn-input" type="text" v-model="text" class="form-control input-sm" placeholder="Type your message here..." />
<span class="input-group-btn">
<button class="btn btn-warning btn-sm" type="button" #click.prevent="send()" id="btn-chat">
Send
</button>
</span>
</div>
<div class="input-group">
<input type="file" multiple class="form-control">
<span class="input-group-btn">
<button class="btn btn-warning btn-sm" type="button" #click.prevent="sendFiles()">
Send Files
</button>
</span>
</div>
</div>
</div>
</div>
<div class="col-md-6 d-flex justify-center">
<video-section></video-section>
</div>
<div id="incomingVideoCallModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Incoming Call</h4>
</div>
<div class="modal-footer">
<button type="button" id="answerCallButton" class="btn btn-success">Answer</button>
<button type="button" id="denyCallButton" data-dismiss="modal" class="btn btn-danger">Deny</button>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-3" v-for="file in conversation.files">
<img :src="file.file_details.webPath" alt="" class="img-responsive">
<a :href="file.file_details.webPath" target="_blank" download>Download - {{ file.name }}</a>
</div>
</div>
</div>
</template>
<script>
$(function () {
var localVideo = document.getElementById('localVideo');
var remoteVideo = document.getElementById('remoteVideo');
var answerButton = document.getElementById('answerCallButton');
answerButton.onclick = answerCall;
$('input[type=file]').on('change', prepareUpload);
});
var files;
var conversationID;
var luid;
var ruid;
var startTime;
var localStream;
var pc;
var offerOptions = {
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
};
var isCaller = false;
var peerConnectionDidCreate = false;
var candidateDidReceived = false;
export default {
props: ['conversation' , 'currentUser'],
data() {
return {
conversationId : this.conversation.conversationId,
channel : this.conversation.channel_name,
messages : this.conversation.messages,
withUser : this.conversation.user,
text : '',
constraints : {
audio: false,
video: true
},
}
},
methods: {
startVideoCallToUser (id) {
Cookies.set('remoteUUID', id);
window.remoteUUID = id;
luid = Cookies.get('uuid');
ruid = Cookies.get('remoteUUID');
isCaller = true;
start()
},
check(id) {
return id === this.currentUser.id;
},
send() {
var self = this;
axios.post('/chat/message/send',{
conversationId : this.conversationId,
text: this.text,
}).then((response) => {
this.listenForNewMessage();
self.text = '';
});
},
sendFiles() {
var data = new FormData();
$.each(files, function(key, value)
{
data.append('files[]', value);
});
data.append('conversationId' , this.conversationId);
axios.post('/chat/message/send/file', data);
},
listenForNewMessage: function () {
Echo.join(this.channel)
.here((users) => {
console.log(users)
})
.listen('\\PhpJunior\\LaravelVideoChat\\Events\\NewConversationMessage', (data) => {
var self = this;
if ( data.files.length > 0 ){
$.each( data.files , function( key, value ) {
self.conversation.files.push(value);
});
}
this.messages.push(data);
})
.listen('\\PhpJunior\\LaravelVideoChat\\Events\\VideoChatStart', (data) => {
if(data.to != this.currentUser.id){
return;
}
if(data.type === 'signal'){
onSignalMessage(data);
}else if(data.type === 'text'){
console.log('received text message from ' + data.from + ', content: ' + data.content);
}else{
console.log('received unknown message type ' + data.type + ' from ' + data.from);
}
});
},
},
beforeMount () {
Cookies.set('uuid', this.currentUser.id);
Cookies.set('conversationID', this.conversationId);
},
mounted() {
this.listenForNewMessage();
}
}
function onSignalMessage(m){
console.log(m.subtype);
if(m.subtype === 'offer'){
console.log('got remote offer from ' + m.from + ', content ' + m.content);
Cookies.set('remoteUUID', m.from);
onSignalOffer(m.content);
}else if(m.subtype === 'answer'){
onSignalAnswer(m.content);
}else if(m.subtype === 'candidate'){
onSignalCandidate(m.content);
}else if(m.subtype === 'close'){
onSignalClose();
}else{
console.log('unknown signal type ' + m.subtype);
}
}
function onSignalClose() {
trace('Ending call');
pc.close();
pc = null;
closeMedia();
clearView();
}
function closeMedia(){
localStream.getTracks().forEach(function(track){track.stop();});
}
function clearView(){
localVideo.srcObject = null;
remoteVideo.srcObject = null;
}
function onSignalCandidate(candidate){
onRemoteIceCandidate(candidate);
}
function onRemoteIceCandidate(candidate){
trace('onRemoteIceCandidate : ' + candidate);
if(peerConnectionDidCreate){
addRemoteCandidate(candidate);
}else{
//remoteCandidates.push(candidate);
var candidates = Cookies.getJSON('candidate');
if(candidateDidReceived){
candidates.push(candidate);
}else{
candidates = [candidate];
candidateDidReceived = true;
}
Cookies.set('candidate', candidates);
}
}
function onSignalAnswer(answer){
onRemoteAnswer(answer);
}
function onRemoteAnswer(answer){
trace('onRemoteAnswer : ' + answer);
pc.setRemoteDescription(answer).then(function(){onSetRemoteSuccess(pc)}, onSetSessionDescriptionError);
}
function onSignalOffer(offer){
Cookies.set('offer', offer);
$('#incomingVideoCallModal').modal('show');
}
function answerCall() {
isCaller = false;
luid = Cookies.get('uuid');
ruid = Cookies.get('remoteUUID');
$('#incomingVideoCallModal').modal('hide');
start()
}
function gotStream(stream) {
trace('Received local stream');
localVideo.srcObject = stream;
localStream = stream;
call()
}
function start() {
trace('Requesting local stream');
navigator.mediaDevices.getUserMedia({
audio: true,
video: {
width: {
exact: 320
},
height: {
exact: 240
}
}
})
.then(gotStream)
.catch(function(e) {
alert('getUserMedia() error: ' + e.name);
});
}
function call() {
conversationID = Cookies.get('conversationID');
trace('Starting call');
startTime = window.performance.now();
var videoTracks = localStream.getVideoTracks();
var audioTracks = localStream.getAudioTracks();
if (videoTracks.length > 0) {
trace('Using video device: ' + videoTracks[0].label);
}
if (audioTracks.length > 0) {
trace('Using audio device: ' + audioTracks[0].label);
}
var configuration = { "iceServers": [{ "urls": "stun:stun.ideasip.com" }] };
pc = new RTCPeerConnection(configuration);
trace('Created local peer connection object pc');
pc.onicecandidate = function(e) {
onIceCandidate(pc, e);
};
pc.oniceconnectionstatechange = function(e) {
onIceStateChange(pc, e);
};
pc.onaddstream = gotRemoteStream;
pc.addStream(localStream);
trace('Added local stream to pc');
peerConnectionDidCreate = true;
if(isCaller) {
trace(' createOffer start');
trace('pc createOffer start');
pc.createOffer(
offerOptions
).then(
onCreateOfferSuccess,
onCreateSessionDescriptionError
);
}else{
onAnswer()
}
}
function onAnswer(){
var remoteOffer = Cookies.getJSON('offer');
pc.setRemoteDescription(remoteOffer).then(function(){onSetRemoteSuccess(pc)}, onSetSessionDescriptionError);
pc.createAnswer().then(
onCreateAnswerSuccess,
onCreateSessionDescriptionError
);
}
function onCreateAnswerSuccess(desc) {
trace('Answer from pc:\n' + desc.sdp);
trace('pc setLocalDescription start');
pc.setLocalDescription(desc).then(
function() {
onSetLocalSuccess(pc);
},
onSetSessionDescriptionError
);
conversationID = Cookies.get('conversationID');
var message = {from: luid, to:ruid, type: 'signal', subtype: 'answer', content: desc, time:new Date()};
axios.post('/trigger/' + conversationID , message );
}
function onSetRemoteSuccess(pc) {
trace(pc + ' setRemoteDescription complete');
applyRemoteCandidates();
}
function applyRemoteCandidates(){
var candidates = Cookies.getJSON('candidate');
for(var candidate in candidates){
addRemoteCandidate(candidates[candidate]);
}
Cookies.remove('candidate');
}
function addRemoteCandidate(candidate){
pc.addIceCandidate(candidate).then(
function() {
onAddIceCandidateSuccess(pc);
},
function(err) {
onAddIceCandidateError(pc, err);
});
}
function onIceCandidate(pc, event) {
if (event.candidate){
trace(pc + ' ICE candidate: \n' + (event.candidate ? event.candidate.candidate : '(null)'));
conversationID = Cookies.get('conversationID');
var message = {from: luid, to:ruid, type: 'signal', subtype: 'candidate', content: event.candidate, time:new Date()};
axios.post('/trigger/' + conversationID , message );
}
}
function onAddIceCandidateSuccess(pc) {
trace(pc + ' addIceCandidate success');
}
function onAddIceCandidateError(pc, error) {
trace(pc + ' failed to add ICE Candidate: ' + error.toString());
}
function onIceStateChange(pc, event) {
if (pc) {
trace(pc + ' ICE state: ' + pc.iceConnectionState);
console.log('ICE state change event: ', event);
}
}
function onCreateSessionDescriptionError(error) {
trace('Failed to create session description: ' + error.toString());
}
function onCreateOfferSuccess(desc) {
trace('Offer from pc\n' + desc.sdp);
trace('pc setLocalDescription start');
pc.setLocalDescription(desc).then(
function() {
onSetLocalSuccess(pc);
},
onSetSessionDescriptionError
);
conversationID = Cookies.get('conversationID');
var message = {from: luid, to:ruid, type: 'signal', subtype: 'offer', content: desc, time:new Date()};
axios.post('/trigger/' + conversationID , message );
}
function onSetLocalSuccess(pc) {
trace( pc + ' setLocalDescription complete');
}
function onSetSessionDescriptionError(error) {
trace('Failed to set session description: ' + error.toString());
}
function gotRemoteStream(e) {
if (remoteVideo.srcObject !== e.stream) {
remoteVideo.srcObject = e.stream;
trace('pc received remote stream');
}
}
function trace(arg) {
var now = (window.performance.now() / 1000).toFixed(3);
console.log(now + ': ', arg);
}
function prepareUpload(event)
{
files = event.target.files;
}
</script>
<style>
.chat
{
list-style: none;
margin: 0;
padding: 0;
}
.chat li
{
margin-bottom: 10px;
padding-bottom: 5px;
border-bottom: 1px dotted #B3A9A9;
}
.chat li.left .chat-body
{
margin-left: 60px;
}
.chat li.right .chat-body
{
margin-right: 60px;
}
.chat li .chat-body p
{
margin: 0;
color: #777777;
}
.panel .slidedown .glyphicon, .chat .glyphicon
{
margin-right: 5px;
}
.panel-body
{
overflow-y: scroll;
height: 250px;
}
::-webkit-scrollbar-track
{
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
background-color: #F5F5F5;
}
::-webkit-scrollbar
{
width: 12px;
background-color: #F5F5F5;
}
::-webkit-scrollbar-thumb
{
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #555;
}
And This is how I am calling my template in my blade template.
#section('content')
<div class="container-fluid">
<chat-room :conversation="{{ $conversation }}" :current-user="{{ auth()->user() }}"></chat-room>
</div>
#endsection
There are no errors in my laravel-echo-server nor in redis server nor in npm but still it is not showing up. I have tried some solutions but none of them are working.
Any help regarding this issue will be appreciated. Thank you in advance.
Can you check in Chrome dev tools for Javascript errors?

Aurelia validation nor working when data is pre-populated in the form

I have been unable to get the validation to work on an edit model-view that has data bound to it in the activate method of its view-model.
I have a created.ts which works on an object with the same fields. This file has almost the same code - the exception is that since this one is a create, no data needs to be loaded to it. In this case, the validation is working properly.
If I comment the code that loads the data for the edit model-view - in the activate method - the validation works properly.
Needless to say I am new to SPA, Aurelia and TypeScript and need some help!!
Below is the code in edit.ts
import { ContactRepository } from "./contactRepository";
import { autoinject } from "aurelia-framework";
import { ContactForEditDto } from "./contactForEditDto";
import { json } from "aurelia-fetch-client";
import { inject, NewInstance } from "aurelia-dependency-injection";
import { ValidationRules, ValidationControllerFactory, validateTrigger,
Validator } from "aurelia-validation";
#autoinject
export class Edit {
public saveStatusMessage: string;
public isSaved: number = -1;
private controller = null;
private validator = null;
public canSave: boolean = false;
constructor(public contactForEdit: ContactForEditDto, private repository:
ContactRepository, private controllerFactory: ValidationControllerFactory,
public contactFullName: string, validator: Validator) {
console.log("starting edit controller");
this.controller = controllerFactory.createForCurrentScope(validator);
this.controller.validateTrigger = validateTrigger.changeOrBlur;
this.validator = validator;
this.controller.subscribe(event => this.validateWhole());
ValidationRules
.ensure((c: ContactForEditDto) => c.contactFirstName)
.displayName("First Name")
.required().withMessage("\${$displayName} cannot be empty.")
.maxLength(50).withMessage("\${$displayName} cannot have more than 50 characters.")
.ensure((c: ContactForEditDto) => c.contactLastName)
.displayName("Last Name")
.required().withMessage("\${$displayName} cannot be empty.")
.maxLength(50).withMessage("\${$displayName} cannot have more than 50 characters.")
.ensure((c: ContactForEditDto) => c.contactEmailAddress)
.displayName("Email Address")
//.required().withMessage("\${$displayName} cannot be empty.")
.email().withMessage("\${$displayName} needs to be in a correct email address format.")
.maxLength(50).withMessage("\${$displayName} cannot have more than 50 characters.")
.ensure((c: ContactForEditDto) => c.contactPhoneNumber)
.displayName("Phone Number")
.required().withMessage("\${$displayName} cannot be empty.")
.maxLength(12).withMessage("\${$displayName} cannot have more than 12 characters.")
.matches(/\d{3}-\d{3}-\d{4}/).withMessage("'${$value}' is not a valid \${$displayName}. Please enter a phone in the format xxx-xxx-xxxx")
.on(ContactForEditDto);
}
// source https://www.jujens.eu/posts/en/2017/Jan/24/aurelia-validation/
workaround 3
validateWhole() {
this.validator.validateObject(this.contactForEdit)
.then(results => this.canSave = results.every(result => result.valid));
}
// Returning data from here because I can return a promise
// and let the router know when i have retrieved my initial data.
// Activate receives a params object as defined in the route.
activate(params) {
console.log("ACTIVATE ON EDIT PARAMS:" + params);
this.repository
.getById(params.id)
.then(data => {
console.log(data);
this.contactForEdit = data;
this.contactFullName = this.contactForEdit.contactLastName + ", " +
this.contactForEdit.contactFirstName; // This needs to come from a method
in
contact.
});
}
edit() {
this.saveStatusMessage = "";
this.isSaved = -1;
// This will be an edit
if (this.contactForEdit.contactId >= 1) {
this.repository
.update(this.contactForEdit)
.then(response => {
if (((response.status == 201) || (response.status == 204))
&& (response.ok == true)) {
this.isSaved = 1;
this.saveStatusMessage = "Successfully saved the contact";
}
else {
this.isSaved = 0;
//response.json().then(json => this.retVal = json);
//TODO: get more details about the error.
if (response.status == 400) {
this.saveStatusMessage = "Unable to save the contact. Please make sure that you entered correct values for every field and try again.";
}
else {
this.saveStatusMessage = "Unable to save the contact.";
}
}
});
}
}
clearContactFields() {
this.contactForEdit = new ContactForEditDto(-1, "", "", "", "");
}
}
Below is the code in edit.html
<template>
<form id="editContact" submit.delegate="edit()">
<!-- placeholder for status messages. If equal to 1 display it. If equals to
-1 or 1 hide this.-->
<div id="successStatusMessage" class.bind="isSaved == 1 ? 'visible' :
'hidden'">
<div id="divSuccessMessage" class="alert alert-success">
×
<!--<span class="glyphicon glyphicon glyphicon-ok" aria-hidden="true">
</span> TODO: How to get the glyphicon working? -->
<span class="sr-only"> Success:</span> ${saveStatusMessage}
</div>
</div>
<!-- placeholder for status messages. If equal to 0 is in error, so dislay error message. if equals to -1 or 1 hide this.-->
<div id="errorStatusMessage" class.bind="isSaved == 0 ? 'visible' : 'hidden'">
<!-- placeholder for status messages. -->
<div id="divErrorMessage" class="alert alert-danger">
×
<!-- <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> TODO: class="glyphicon glyphicon-exclamation-sign" how to get these in here for class? -->
<span class="sr-only"> Error:</span> ${saveStatusMessage}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
<!--<div if.bind="isCreate">
"Create a Contact"
</div>
<div if.bind="!isCreate">
Edit ${contactForEdit.contactFirstName}
</div>-->
${ "Edit " + contactFullName }
</div>
</div>
<div class="panel-body">
<div class="form-horizontal">
<div class="form-group" validation-errors.bind="editFirstNameErrors"
class.bind="editFirstNameErrors.length ? 'has-error' : ''">
<label class="control-label col-md-2">First Name: </label>
<div class="col-md-10">
<input type="text"
placeholder="First Name"
class="form-control"
value.bind="contactForEdit.contactFirstName & validate" required /> <!-- NO ${} !!!-->
<span class="help-block" repeat.for="editErrorInfo of editFirstNameErrors">
${editErrorInfo.error.message}
</span>
</div>
</div>
<div class="form-group" validation-errors.bind="editLastNameErrors"
class.bind="editLastNameErrors.length ? 'has-error' : ''">
<label class="control-label col-md-2">Last Name: </label>
<div class="col-md-10">
<input type="text"
placeholder="Last Name"
class="form-control"
value.bind="contactForEdit.contactLastName & validate" required /> <!-- NO ${} !!!-->
<span class="help-block" repeat.for="editErrorInfo of editLastNameErrors">
${editErrorInfo.error.message}
</span>
</div>
</div>
<div class="form-group" validation-errors.bind="emailErrors"
class.bind="editEmailErrors.length ? 'has-error' : ''">
<label for="emailAddress" class="control-label col-md-2">Email: </label>
<div class="col-md-10">
<input id="emailAddress"
type="text"
placeholder="Email Address (format: email#domain.com)"
class="form-control"
value.bind="contactForEdit.contactEmailAddress & validate" /> <!-- NO ${} !!!-->
<span class="help-block" repeat.for="editErrorInfo of editEmailErrors">
${editErrorInfo.error.message}
</span>
</div>
</div>
<div class="form-group" validation-errors.bind="editPhoneErrors"
class.bind="editPhoneErrors.length ? 'has-error' : ''">
<label class="control-label col-md-2">Phone: </label>
<div class="col-md-10">
<input type="text"
placeholder="Phone Number (format: xxx-xxx-xxxx)"
class="form-control"
value.bind="contactForEdit.contactPhoneNumber & validate" required /> <!-- NO ${} !!!-->
<span class="help-block" repeat.for="editErrorInfo of editPhoneErrors">
${editErrorInfo.error.message}
</span>
</div>
</div>
<button type="submit" class="btn btn-default ${canSave ? '' : 'disabled'}">
<!-- Look at click.dependent when there are child with buttons calling this.-->
Save
</button>
<!-- AA-10-17-17 - replaced with errors per input field. <ul for.bind="controller.errors">
<li repeat.for="error of controller.errors" style="color:red">
${error.message}
</li>
</ul>-->
</div>
</div>
</div>
</form>
<div>
<a route-href="route: home"
class="btn btn-default">
Back to list
</a>
</div>
</template>
I expect it's because of this code:
.getById(params.id)
.then(data => {
console.log(data);
this.contactForEdit = data;
your validation is against a ContactForEditDto object, but my guess is your repository is returning a JSON object cast to a ContactForEditDto, so it's not actually a class at all.
Try something like
console.log(data);
this.contactForEdit = new ContactForEditDto(data.id, data.firstname ..etc..);
or
console.log(data);
this.contactForEdit = Object.assign(new ContactForEditDto(), data);
We just had a similar problem and solved it by setting up our validations after assigning the remote data to our local field. In your code, you'd set up your validation rules after this.contactForEdit = data;

Resources