How to create and access Socket IO server in nuxt3 - websocket

Here i will show how to create and access socket io server in newest nuxt v.3, for many developers migration from .2 may be difficult beacause of new features.

This will create your socket io server
// modules/ws-server.ts
import { Server } from 'socket.io'
import { defineNuxtModule } from '#nuxt/kit'
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('listen', async (server) => {
const io = new Server(server)
nuxt.hook('close', () => io.close())
io.on('connection', (socket) => {
console.log(`Socket connected: ${socket.id}`)
})
})
}
})
Now we want to access socket in front-end:
// plugins/socket.io.ts
import io from 'socket.io-client'
export default defineNuxtPlugin(() => {
const socket = io(useRuntimeConfig().url)
return {
provide: {
io: socket
}
}
})
```ts
Now import module & plugin into nuxt config:
// nuxt.config.ts
...
modules: ['./modules/ws-server']
...
Here's example of usage in component:
```vue
<template>
<button #click="func()" class="bt">
<slot>Button</slot>
</button>
</template>
<script slang="ts">
export default {
data: () => ({
}),
methods: {
func() {
this.$io.emit('event_name', {})
}
}
}
</script>
<style lang="scss" scoped>
.bt {
background: #202225;
outline: none;
border: none;
color: #fff;
font-family: proxima-nova, sans-serif;
padding: 5px 10px;
border-radius: 5px;
transition: 200ms;
cursor: pointer;
&:hover {
background: #272a2e;
}
}
</style>

Related

Microsoft Botframework webchat. How to fix issue with activityMiddleware and showAvatarInGroup after update to 4.14

Working from the minimizable webchat sample (react) a custom typing indicator is added that renders as soon as the bot sends an typingIndicator event:
await context.sendActivity({ name: 'typingIndicator', type: 'event' });
In WebChat.js
import TypingIndicator from './TypingIndicator';
const activityMiddleware = () => next => ({ activity, nextVisibleActivity, ...otherArgs }) => {
const { name } = activity;
// first remove all existing typing indicators from the DOM
let elements = document.getElementsByClassName('typing-indicator');
for (var i = 0; i < elements.length; i++) {
elements[i].style.display = 'none'
}
// if typing indicator event received from the bot, return one to be rendered
if (name === 'typingIndicator') {
return () => <TypingIndicator activity={activity} nextVisibleActivity={nextVisibleActivity} />;
}
else {
return next({ activity, nextVisibleActivity, ...otherArgs });
}
};
TypingIndicator.js
import React from 'react';
import './TypingIndicator.css';
const TypingIndicator = () => {
return (
<div className="typing-indicator">
<span></span>
<span></span>
<span></span>
</div>
);
};
export default TypingIndicator
TypingIndicator.css
.typing-indicator {
background-color: transparent;
height: 35px;
width: 60px!important;
border-radius: 20px;
padding:10px;
margin-left: 70px;
}
.typing-indicator span {
line-height: 35px;
display:inline-block;
vertical-align: middle;
height: 10px;
width: 10px;
margin: 0 1px;
background-color: #9E9EA1;
border-radius: 50%;
opacity: 0.4;
animation: bounce 0.7s linear infinite;
}
.typing-indicator span:nth-child(1)
{
animation-delay: 0.1s;
}
.typing-indicator span:nth-child(2)
{
animation-delay: 0.2s;
}
.typing-indicator span:nth-child(3)
{
animation-delay: 0.1s;
}
#keyframes bounce {
30% { transform: translateY(-4px); }
60% { transform: translateY(0px); }
80% { transform: translateY(4px); }
100% { transform: translateY(0px); opacity: 0.5; }
}
This worked fine in 4.9. Afer updating to 4.14 it still works until I decided to only show one avatar for each group of activities:
const styleOptions = {
showAvatarInGroup: 'sender',
...
}
As soon as I add this option to styleOptions, the Bot avatar is not shown anymore. As soon as I change the setting to something else, the botAvatar is shown again.
As soon as I remove the activityMiddleware, I am able to show one avatar per group of activities.
[Update]
I did some additional digging and narrowed it down to my botcode.
.1 Installed webchat sample d.reaction-buttons
.2 Added Styleoptions to show bot avatar
.3 Added ShowAvatarInGroup: 'sender'
This works fine. The BotAvator is shown
But as soon as I replace the webchat-mockbot with my own bot, the problem returns:
ShowAvatarInGroup: 'sender' -> Not bot avatar
ShowAvatarInGroup: '' -> bot avatar
In both cases the console is showing these error messages:
Not sure whats causing this. Was never a problem before. I will try and figure out what I am sending to webchat that's breaking the rendering of botAvatar
[Update2]
According to webchats changelog, I need to rewrite the activity midleware to something like this:
() => next => (...setupArgs) => {
const render = next(...setupArgs);
return render && (...renderArgs) => {
const element = render(...renderArgs);
return element && <div>{element}</div>;
};
}
I can't get this to work for my purpose however. My typingIndicator reactelement is not being rendered if I use it like this.
Any guidance on how to fix this, is much appreciated.

Error in mounted hook: "TypeError: edge is undefined" when using dagre-d3 with vue2

I'm trying to set up very simple example with Vue2 using dagre-d3 for rendering directed graphs.
Unfortunately, even with extremely simple example, it wont work. Examples found elsewhere online are using older version of d3.
Currently, Vue2 app is mostly default template with a router with a typescript as language. Diagram component is in javascript (due to missing types in my code for d3 and dagre-d3).
When running the component mentioned below, following error happens and nothing is shown in the <svg> block.
Error in mounted hook: "TypeError: edge is undefined"
And it happens on this line
render(container, g);
Only thing i can think off is that i might be missing some some dependencies or that all components must be typescript.
Help?
Diagram.vue:
<template>
<div class="myback">
<h1>This is a diagram component</h1>
<svg>
<g></g>
</svg>
</div>
</template>
<script>
import * as d3 from "d3";
import dagreD3 from "dagre-d3";
// let edges = {}
// let nodes = {}
// let g = new dagreD3.graphlib.Graph().setGraph({})
export default {
/*
data () {
return {
edges: {},
nodes: {}
}
},
*/
mounted() {
/* create graph itself */
const g = new dagreD3.graphlib.Graph().setGraph({});
g.setGraph({
nodesep: 70,
ranksep: 50,
rankdir: "LR",
marginx: 20,
marginy: 20,
});
console.log(g);
const render = new dagreD3.render(); // eslint-disable-line new-cap
console.log(render);
const svg = d3.select("svg");
const container = svg.select("g");
console.log(svg);
console.log(container);
/* define zoom behavior */
function zoomed(e) {
container.attr("transform", e.transform);
}
const zoom = d3.zoom().scaleExtent([1, 10]).on("zoom", zoomed);
g.setNode("kspacey", { label: "Kevin Spacey", width: 144, height: 100 });
g.setNode("blabla", { label: "blabla", width: 144, height: 100 });
g.setEdge("kspacey", "blabla");
svg.call(zoom);
render(container, g);
},
/*
methods: {
draw () {
}
}
*/
};
</script>
<style scoped>
section {
margin-bottom: 3em;
}
section p {
text-align: justify;
}
svg {
border: 1px solid #ccc;
overflow: hidden;
margin: 0 auto;
background: white;
width: 800px;
height: 600px;
}
text {
font-weight: 300;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
font-size: 14px;
}
path.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}
.node rect {
stroke: #333;
fill: #fff;
stroke-width: 1.5px;
}
.myback {
background: gray;
}
</style>
Codesanbox link is here
There were two problems with this component:
Default edge label needs to be set
I was missing a call on the graph instantiation. It should have been
const g = new dagreD3.graphlib.Graph()
.setGraph({})
.setDefaultEdgeLabel(function () { return {} })
d3.select() was selecting and using wrong node for rendering. Due to usage of fontawesome, in the router-link, i was using following
<router-link to="/about">
<font-awesome-icon :icon="['fas', 'info-circle']" />
</router-link>
Because the font-awesome-icon is rendered to <svg> element, rendering was happening in that node, but i only noticed this after fix with the default edge.
If someone has the same issue, this example was the one that helped me identify explained issues

Autosave Status in CKEditor 5

I have gotten stuck on a rather simple aspect of the autosave feature and that is the current status of the action like found on the overview page: https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/saving-data.html#demo. But it doesn't look like they actually reference it anywhere (example below).
My html is just:
<textarea class="form-control" name="notes" id="notes">{!! $shipmentShortage->notes !!}</textarea>
My create script is below, the autosave feature works just fine, but the status just isn't there:
<script>
ClassicEditor
.create( document.querySelector( '#notes' ), {
toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ],
image: {
toolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ],
},
autosave: {
save( editor ) {
console.log(editor.getData());
// The saveData() function must return a promise
// which should be resolved when the data is successfully saved.
return saveData( editor.getData() );
}
}
} );
// Save the data to a fake HTTP server (emulated here with a setTimeout()).
function saveData( data ) {
return new Promise( resolve => {
setTimeout( () => {
console.log( 'Saved', data );
$.ajax({
url: '/osd/shortages/update',
type: 'POST',
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
data: {
'shortage_id':'{{$shipmentShortage->id}}',
'notes': data,
},
dataType: 'json',
success: function (response) {
console.log('saved');
}
});
resolve();
}, 5000 );
} );
}
// Update the "Status: Saving..." info.
function displayStatus( editor ) {
const pendingActions = editor.plugins.get( 'PendingActions' );
const statusIndicator = document.querySelector( '#editor-status' );
pendingActions.on( 'change:hasAny', ( evt, propertyName, newValue ) => {
if ( newValue ) {
statusIndicator.classList.add( 'busy' );
} else {
statusIndicator.classList.remove( 'busy' );
}
} );
}
</script>
You are absolutely correct. They show us a sexy status updater but don't give us the code for it. Here is what I extracted from the demo page by looking at the page source. This should give you the Status updates as you asked. Let me know if you have any questions.
HTML:
<div id="snippet-autosave">
<textarea name="content" id="CKeditor_Notes">
Sample text
</textarea>
</div>
<!-- This will show the save status -->
<div id="snippet-autosave-header">
<div id="snippet-autosave-status" class="">
<div id="snippet-autosave-status_label">Status:</div>
<div id="snippet-autosave-status_spinner">
<span id="snippet-autosave-status_spinner-label"></span>
<span id="snippet-autosave-status_spinner-loader"></span>
</div>
</div>
</div>
CSS:
<style>
#snippet-autosave-header{
display: flex;
justify-content: space-between;
align-items: center;
background: var(--ck-color-toolbar-background);
border: 1px solid var(--ck-color-toolbar-border);
padding: 10px;
border-radius: var(--ck-border-radius);
/*margin-top: -1.5em;*/
margin-bottom: 1.5em;
border-top: 0;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
#snippet-autosave-status_spinner {
display: flex;
align-items: center;
position: relative;
}
#snippet-autosave-status_spinner-label {
position: relative;
}
#snippet-autosave-status_spinner-label::after {
content: 'Saved!';
color: green;
display: inline-block;
margin-right: var(--ck-spacing-medium);
}
/* During "Saving" display spinner and change content of label. */
#snippet-autosave-status.busy #snippet-autosave-status_spinner-label::after {
content: 'Saving...';
color: red;
}
#snippet-autosave-status.busy #snippet-autosave-status_spinner-loader {
display: block;
width: 16px;
height: 16px;
border-radius: 50%;
border-top: 3px solid hsl(0, 0%, 70%);
border-right: 2px solid transparent;
animation: autosave-status-spinner 1s linear infinite;
}
#snippet-autosave-status,
#snippet-autosave-server {
display: flex;
align-items: center;
}
#snippet-autosave-server_label,
#snippet-autosave-status_label {
font-weight: bold;
margin-right: var(--ck-spacing-medium);
}
#snippet-autosave + .ck.ck-editor .ck-editor__editable {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
#snippet-autosave-lag {
padding: 4px;
}
#snippet-autosave-console {
max-height: 300px;
overflow: auto;
white-space: normal;
background: #2b2c26;
transition: background-color 500ms;
}
#snippet-autosave-console.updated {
background: green;
}
#keyframes autosave-status-spinner {
to {
transform: rotate( 360deg );
}
}
</style>
The rest is just initializing the Editor just like on the demo page here.
ClassicEditor
.create(document.querySelector('#CKeditor_Notes'), {
autosave: {
save(editor) {
return saveData(editor.getData());
}
}
})
.then(editor => {
window.editor = editor;
displayStatus(editor);
})
.catch(err => {
console.error(err.stack);
});
// Save the data to Server Side DB.
function saveData(data) {
return new Promise(resolve => {
setTimeout(() => {
console.log('Saved', data);
SaveDataToDB(data)
resolve();
});
});
}
// Update the "Status: Saving..." info.
function displayStatus(editor) {
const pendingActions = editor.plugins.get('PendingActions');
const statusIndicator = document.querySelector('#snippet-autosave-status');
pendingActions.on('change:hasAny', (evt, propertyName, newValue) => {
if (newValue) {
statusIndicator.classList.add('busy');
} else {
statusIndicator.classList.remove('busy');
}
});
}

CSS Modules <style module> doesnt work

I have Laravel 5.4 project with Vue.js. I wont to use CSS Modules feature that provides by vue-loader. I have vue.js file with code:
<template lang="pug">
.LAYOUT
.SIDE-NAVBAR
.MAIN
</template>
<style module>
.LAYOUT{
height: 100%;
width: 100%;
border: 1px solid red;
}
</style>
<script>
export default {
methods:{
test(){
console.log(this.$style.LAYOUT)
}
},
mounted(){
this.test();
}
}
</script>
When I'm trying to see some information about "this.$style.LAYOUT" in console, it shows that the variable is undefined. May be I should do some settings? How to fix it?
When I'm trying to get value of "this.$style", it returns object:
It may be undefined because you not using that class.
Below is a working example.It also includes how to set dynamic css module class:
<template>
<div>
<button :class="[className1, className2, dynamicClass]" #click="showStyleObject">Click Me</button>
</div>
</template>
<script>
export default {
name: 'example',
props: {
'type-of-button': {
validator: function (value) {
return ['primary', 'secondary', 'default'].indexOf(value) !== -1
}
}
},
data() {
return {
className1: this.$style.button,
className2: this.$style.button2,
}
},
created() {
console.log(this.$style.button)
console.log(this.$style.button2)
},
computed: {
dynamicClass() {
return this.$style[this.typeOfButton]
}
},
methods: {
showStyleObject() {
console.log(this.$style)
}
},
}
</script>
<style module>
.button {
background: red;
}
.button2 {
padding: 8px 10px;
}
.primary {
padding: 8px 10px;
background: blue;
color: white;
border-radius: 10px;
}
.secondary {
padding: 8px 15px;
background: darkslategrey;
color: aliceblue;
border: none;
}
.default {
background: aliceblue;
}
</style>

Issue while calling web api controller from service in angular2

I am doing angular quick start tutorial.
So I am just Hero tutorial that specifies in angular2 quickstart on its website.
That runs fine for me. it binds static array data and perform CRUD.
But now I want to learn how to call web API method for getting data from database.
So I am calling webapi method in getHeroes() method of service and calling that method from init method-ngOnInit() of component but it gives error like this.
please correct if I am wrong.
Got this error, while calling Web api controller from my service in angular2
EXCEPTION:
Error: Uncaught (in promise): No provider for Http! (DashboardComponent -> HeroService -> Http)BrowserDomAdapter.logError # angular2.dev.js:23925
angular2.dev.js:23925 STACKTRACE:BrowserDomAdapter.logError # angular2.dev.js:23925
angular2.dev.js:23925 Error: Uncaught (in promise): No provider for Http! (DashboardComponent -> HeroService -> Http)
at resolvePromise (angular2-polyfills.js:602)
at angular2-polyfills.js:579
at ZoneDelegate.invoke (angular2-polyfills.js:390)
at Object.NgZoneImpl.inner.inner.fork.onInvoke (angular2.dev.js:2126)
at ZoneDelegate.invoke (angular2-polyfills.js:389)
at Zone.run (angular2-polyfills.js:283)
at angular2-polyfills.js:635
at ZoneDelegate.invokeTask (angular2-polyfills.js:423)
at Object.NgZoneImpl.inner.inner.fork.onInvokeTask (angular2.dev.js:2118)
at ZoneDelegate.invokeTask (angular2-polyfills.js:422)BrowserDomAdapter.logError # angular2.dev.js:23925
angular2-polyfills.js:528 Unhandled Promise rejection: No provider for Http! (DashboardComponent -> HeroService -> Http) ; Zone: angular ; Task: Promise.then ; Value: NoProviderErrorconsoleError # angular2-polyfills.js:528
angular2-polyfills.js:530 Error: Uncaught (in promise): No provider for Http! (DashboardComponent -> HeroService -> Http)(…)consoleError # angular2-polyfills.js:530
Here is my Hero service:
import {Injectable} from 'angular2/core';
import {Http,Response,Headers} from 'angular2/http';
import 'rxjs/add/operator/map'
import {Observable} from 'rxjs/Observable';
import {Hero} from '/Scripts/FirstEx_Ts/Hero.ts';
import {HEROES} from '/Scripts/FirstEx_Ts/MockHeros.ts';
#Injectable()
export class HeroService {
private headers: Headers;
constructor(private _http:Http) {
}
getHeroes(){
return this._http.get("http://localhost:54046/api/Heromanage/GetAllHeroes")
.map((response: Response) => <Hero[]>response.json())
.catch(this.handleError);
}
getHeroesSlowly() {
return new Promise<Hero[]>(resolve =>
setTimeout(() => resolve(HEROES), 2000) // 2 seconds
);
}
getHero(id: number) {
return Promise.resolve(HEROES).then(
heroes => heroes.filter(hero => hero.id === id)[0]
);
}
private handleError(error: Response) {
console.error(error);
return Observable.throw(error.json().error || 'Server error');
}
}
And here is my Component from where I am calling service method:
import {Component, OnInit} from 'angular2/core';
import {Http,Response,Headers} from 'angular2/http';
import { CORE_DIRECTIVES } from 'angular2/common';
import {Router} from 'angular2/router';
import {Hero} from '/Scripts/FirstEx_Ts/Hero.ts';
import {HeroService} from '/Scripts/FirstEx_Ts/HeroService.ts';
#Component({
selector: 'my-dashboard',
providers: [HeroService],
templateUrl: '/Templates/DashboardComponent.html',
directives: [CORE_DIRECTIVES],
styles: [ `
[class*='col-'] {
float: left;
}
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h3 {
text-align: center; margin-bottom: 0;
}
[class*='col-'] {
padding-right: 20px;
padding-bottom: 20px;
}
[class*='col-']:last-of-type {
padding-right: 0;
}
.grid {
margin: 0;
}
.col-1-4 {
width: 25%;
}
.module {
padding: 20px;
text-align: center;
color: #eee;
max-height: 120px;
min-width: 120px;
background-color: #607D8B;
border-radius: 2px;
}
h4 {
position: relative;
}
.module:hover {
background-color: #EEE;
cursor: pointer;
color: #607d8b;
}
.grid-pad {
padding: 10px 0;
}
.grid-pad > [class*='col-']:last-of-type {
padding-right: 20px;
}
#media (max-width: 600px) {
.module {
font-size: 10px;
max-height: 75px; }
}
#media (max-width: 1024px) {
.grid {
margin: 0;
}
.module {
min-width: 60px;
}
}
`]
})
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(
private _router: Router,
private _heroService: HeroService) {
debugger;
}
**ngOnInit() {
alert('hi');
debugger;
this._heroService
.getHeroes()
.subscribe((heroes:Hero[]) => this.heroes = data,
error => console.log(error),
() => console.log('Get all Items complete'));
}**
gotoDetail(hero: Hero) {
let link = ['HeroDetail', { id: hero.id }];
this._router.navigate(link);
}
}
you may try below,
Angular version < RC5
include HTTP_PROVIDERS in the providers array of Component metadata.
Angular version >= RC5
import HttpModule in the Module containing your component.
Hope this helps!!

Resources