I try to integrate (vue-i18n) at this library (https://github.com/mattmezza/vue-beautiful-chat) in src folder but I have some integration problems
so,
in this file ./i18n/translations.js => we have the translations
in src/index.js
import Launcher from './Launcher.vue'
import VTooltip from 'v-tooltip'
import VueI18n from 'vue-i18n'
import messages from './i18n/translations.js'
const defaultComponentName = 'beautiful-chat'
const Plugin = {
install (Vue, options = {}) {
/**
* Makes sure that plugin can be installed only once
*/
if (this.installed) {
return
}
Vue.use(VueI18n)
const locale = navigator.language
const i18n = new VueI18n({
fallbackLocale: 'fr',
locale: locale,
messages
})
this.installed = true
this.event = new Vue({i18n})
this.dynamicContainer = null
this.componentName = options.componentName || defaultComponentName
/**
* Plugin API
*/
Vue.prototype.$chat = {
_setDynamicContainer (dynamicContainer) {
Plugin.dynamicContainer = dynamicContainer
}
}
/**
* Sets custom component name (if provided)
*/
Vue.component(this.componentName, Launcher)
Vue.use(VTooltip)
Vue.use(VueI18n)
}
}
export default Plugin
And i start to change in the file "src/Launcher.vue" "you" in the header of the chat
computed: {
chatWindowTitle() {
if (this.title !== '') {
return this.title
}
if (this.participants.length === 0) {
return $t('participant.you_only')
} else if (this.participants.length > 1) {
return $t('participant.you_and_participants', { participant: 'this.participants[0].name' })
} else {
return 'You & ' + this.participants[0].name
}
}
},
but i receive this error
i have try few others methods as this.$i18n and others.
Can you help me please ?
Thanks a lot.
Are you possible missing the "this" when referring to "$t" on the computed property?
computed: {
chatWindowTitle() {
if (this.title !== '') {
return this.title
}
if (this.participants.length === 0) {
return this.$t('participant.you_only')
} else if (this.participants.length > 1) {
return this.$t('participant.you_and_participants', { participant: 'this.participants[0].name' })
} else {
return 'You & ' + this.participants[0].name
}
}
},
Related
I am currently working on web components and shadow DOM.
I can see that it is possible to create a native web component using Vue3 here
Vue docs. But I am currently facing issues building the native component file from vuejs files. I have googled for some time and found there are not many helpful content for it.
Building Web Components with Vue 3.2 is by far the most helpful blog I have found. Still I am unable to do production build of my files.
Currently I am getting 2 files after build.
import {
r as c,
c as l,
o as a,
a as u,
b as d,
d as f,
t as m,
u as p,
e as g,
} from "./vendor.21fe8919.js";
const y = function () {
const r = document.createElement("link").relList;
if (r && r.supports && r.supports("modulepreload")) return;
for (const e of document.querySelectorAll('link[rel="modulepreload"]')) o(e);
new MutationObserver((e) => {
for (const t of e)
if (t.type === "childList")
for (const s of t.addedNodes)
s.tagName === "LINK" && s.rel === "modulepreload" && o(s);
}).observe(document, { childList: !0, subtree: !0 });
function i(e) {
const t = {};
return (
e.integrity && (t.integrity = e.integrity),
e.referrerpolicy && (t.referrerPolicy = e.referrerpolicy),
e.crossorigin === "use-credentials"
? (t.credentials = "include")
: e.crossorigin === "anonymous"
? (t.credentials = "omit")
: (t.credentials = "same-origin"),
t
);
}
function o(e) {
if (e.ep) return;
e.ep = !0;
const t = i(e);
fetch(e.href, t);
}
};
y();
const h = {
props: { timeZone: { type: String, default: "America/Los_Angeles" } },
emits: ["datechange"],
setup(n, { emit: r }) {
const i = n,
o = c(new Date()),
e = l(() => o.value.toLocaleString("en-US", { timeZone: i.timeZone }));
return (
setInterval(() => {
(o.value = new Date()), r("datechange", e);
}, 1e3),
(t, s) => (
a(), u("div", null, [d(t.$slots, "prefix"), f(" " + m(p(e)), 1)])
)
);
},
},
v = g(h);
customElements.define("current-time", v);
document.querySelector("current-time").addEventListener("datechange", L);
function L(n) {
console.log(n.detail[0].value);
}
But i would like the build file to be in following format for my use case.
class CurrentTime extends HTMLElement {
connectedCallback() {
this.innerHTML = new Date();
setInterval(() => this.innerHTML = new Date(), 1000)
}
}
// Define it as a custom element
customElements.define('current-time', CurrentTime);
vite config file
import { defineConfig } from "vite";
import vue from "#vitejs/plugin-vue";
export default defineConfig({
plugins: [vue({ customElement: true })],
});
I get the "object is not a function" error on the line where the "setup()" function appears.
I have no clue how to debug this... Am I doing something wrong? (I'm not an experimented developer, so I know I'm doing things wrong, but here, I have no clue what it is...)
It's asking me to add more details because my post is mainly code... So I'm writing this, but I habe idea what details I could c=possibly add. :-)
Thanks in advance for your help!!
<script>
import { ref } from 'vue'
import Ftable from '#/components/tables/Ftable.vue'
import Searchbar from '#/components/tables/Searchbar.vue'
import getMainCollection from '#/composables/getMainCollection'
export default {
name: 'Home',
components: { Searchbar, Ftable },
setup(){ //error arrives on this line
const { getData, getMore } = getMainCollection()
const documents = ref('')
const lastVisible = ref('')
const type = ref('')
const country = ref('')
function newSearch() {
const {doc, last} = getData(type, country)
documents.value = doc
lastVisible.Value = last
}
function askForMore() {
const { doc, last } = getMore(type, country, lastVisible)
documents.value = doc
lastVisible.value = last
}
return { documents, askForMore, newSearch, askForMore }
}
}
</script>
import { ref } from 'vue'
import { projectFirestore } from '#/firebase/config'
const getMainCollection = () => {
const collectionGroupRef = projectFirestore.collectionGroup('users')
const lastVisible = ref('')
const documents = ('')
function getData(type, country) {
const filter = null
if (type != null && country == null){
filter = collectionGroupRef.where('type', '==', `${type}`)
}
else if(type == null && country != null){
filter = collectionGroupRef.where('country', '==', `${country}`)
}
else{
filter = collectionGroupRef
}
const data = filter.orderBy('createdAt')
.limit(2)
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
documents.value.push({ ...doc.data(), id: doc.id})
})
lastVisible = querySnapshot.docs[querySnapshot.docs.length-1]
})
return( documents, lastVisible)
}
function getMore(type, country, lastVisible) {
const filter = null
if (type != null && country == null){
filter = collectionGroupRef.where('type', '==', `${type}`)
}
else if(type == null && country != null){
filter = collectionGroupRef.where('country', '==', `${country}`)
}
else{
filter = collectionGroupRef
}
filter.startAfter(lastVisible)
.limit(2)
.orderBy(createdAt)
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
documents.value.push({ ...doc.data(), id: doc.id })
})
lastVisible = querySnapshot.docs[querySnapshot.docs.length-1]
})
return( documents, lastVisible)
}
return ( getData, getMore )
}
export { getMainCollection }
Since you exported getMainCollection as an object:
export { getMainConnection }
You need to destructure it when importing:
import { getMainCollection } from '#/composables/getMainCollection'
I'm using Quasar for SPA only. But I don't need all the things that come with Quasar CLI.
Is there a way to eject Quasar CLI and start using Vue + Quasar UMD?
Basically, stop using quasar dev and start using vue serve?
Yes, you can. The following changes should be made:
// vue.config.js
const QuasarLoader = require('./quasar-loader/index');
module.exports =
{
css:
{
loaderOptions:
{
scss:
{
prependData: `#import "~quasar/src/css/variables.sass";`
}
}
},
transpileDependencies: ['quasar'],
configureWebpack: (config) =>
{
if (!config.plugins) config.plugins = [];
config.plugins.push(new QuasarLoader());
},
}
// quasar-loader/auto-import.js
/**
* Quasar runtime for auto-importing
* components or directives.
*
* Warning! This file does NOT get transpiled by Babel
* but is included into the UI code.
*
* #param component {Vue} Component object
* #param type {String} One of 'components' or 'directives'
* #param items {Object} Object containing components or directives
*/
module.exports = function quasarLoader(component, type, items)
{
/* we use a workaround in functional templates
<template>
<component :is="$options.components.QBtn" ... />
</template>
*/
var target, i;
var opt = component.options;
if (!opt[type])
{
opt[type] = items
}
else
{
target = opt[type];
for (i in items)
{
if (!target[i])
{
target[i] = items[i]
}
}
}
};
// quasar-loader/index.js
const RuleSet = require('webpack/lib/RuleSet');
let vueLoaderPath;
try
{
vueLoaderPath = require.resolve('vue-loader');
}
catch (err)
{}
function isVueLoader(use)
{
return use.ident === 'vue-loader-options' ||
use.loader === 'vue-loader' ||
(vueLoaderPath && use.loader === vueLoaderPath)
}
class QuasarLoaderPlugin
{
constructor(options)
{
this.options = options || {}
}
apply(compiler)
{
// use webpack's RuleSet utility to normalize user rules
const rawRules = compiler.options.module.rules;
const { rules } = new RuleSet(rawRules);
// find the rule that applies to vue files
const vueRuleIndex = rules.findIndex(rule => rule.use && rule.use.find(isVueLoader));
const vueRule = rules[vueRuleIndex];
if (!vueRule)
{
throw new Error(
`[QuasarLoaderPlugin Error] No matching rule for vue-loader found.\n` +
`Make sure there is at least one root-level rule that uses vue-loader.`
)
}
vueRule.use.unshift({
loader: require.resolve('./loader'),
options: this.options || { nameCase: 'kebab' }
});
compiler.options.module.rules = rules;
}
}
module.exports = QuasarLoaderPlugin;
// quasar-loader/loader.js
const path = require('path');
const compiler = require('vue-template-compiler');
// const loaderOptions = require('loader-utils/lib/getOptions');
const stringifyRequest = require('loader-utils/lib/stringifyRequest');
const importData = require('quasar/dist/babel-transforms/auto-import.json');
const importTransform = require('quasar/dist/babel-transforms/imports.js');
const runtimePath = require.resolve('./auto-import.js');
// regex to match functional components
const funcCompRegex = new RegExp(
'var\\s+component\\s*=\\s*normalizer\\((?:[^,]+,){3}\\s*true,'
);
function transform(itemArray)
{
return itemArray
.map(name => `import ${name} from '${importTransform(name)}'`)
.join(`\n`)
}
module.exports = async function (content, sourceMap)
{
this.async();
this.cacheable();
if (!this.resourceQuery)
{
const readFile = path => new Promise((resolve, reject) =>
{
this.fs.readFile(path, function (err, data)
{
if (err) reject(err);
else resolve(data)
})
});
this.addDependency(this.resourcePath);
const tags = new Set();
const directives = new Set();
const file = (await readFile(this.resourcePath)).toString('utf8');
const component = compiler.parseComponent(file);
if (component.template)
{
if (component.template.src)
{
const externalFile = (await new Promise((resolve, reject) =>
this.resolve(path.dirname(this.resourcePath), component.template.src, (err, result) =>
{
if (err) reject(err);
else resolve(result)
})
));
component.template.content = (await readFile(externalFile)).toString('utf8'); // external content
}
const compRegexKebab = new RegExp('^' + importData.regex.kebabComponents + '$');
const compRegexPascal = new RegExp('^' + importData.regex.pascalComponents + '$');
const dirRegex = new RegExp('^' + importData.regex.directives + '$');
compiler.compile(component.template.content, {
modules: [{
postTransformNode: node =>
{
if ("directives" in node)
{
node.directives.forEach(({ name }) =>
{
if (dirRegex.test('v-' + name))
{
directives.add(importData.importName['v-' + name]);
}
});
}
if (compRegexKebab.test(node.tag))
{
tags.add(importData.importName[node.tag]);
}
else if (compRegexPascal.test(node.tag))
{
tags.add(node.tag);
}
}
}]
});
const arrTags = [...tags];
const arrDirs = [...directives];
if (arrTags.length > 0 || arrDirs.length > 0)
{
const functional = funcCompRegex.test(content);
let newContent = '/* quasar-loader */\n';
newContent += `import qInstall from ${stringifyRequest(this, runtimePath)}\n`;
if (arrTags.length > 0)
{
if (functional) console.error('Using workaround for local Vue components (' + arrTags.join(',') + ') in a functional template.');
newContent += transform(arrTags) + '\n';
newContent += `qInstall(component, "components", {${arrTags.join(",")}})\n`;
}
if (arrDirs.length > 0)
{
if (functional) console.error('Using local Vue directive (' + arrDirs.join(',') + ') in a functional component is not supported.');
newContent += transform(arrDirs) + '\n';
newContent += `qInstall(component, "directives", {${arrDirs.join(",")}})\n`;
}
// Insert our modification before the HMR code
const hotReload = content.indexOf('/* hot reload */');
if (hotReload > -1)
{
content = content.slice(0, hotReload) + newContent + '\n\n' + content.slice(hotReload)
}
else
{
content += '\n\n' + newContent
}
}
}
}
this.callback(null, content, sourceMap);
};
// src/main.js
import QuasarInstall from 'quasar/src/vue-plugin'
import iconSet from 'quasar/icon-set/svg-mdi-v5'
// import QuasarDialog from 'quasar/src/plugins/Dialog'
import '#/assets/scss/quasar.scss'
QuasarInstall.install(Vue, {
iconSet,
plugins:
{
// Dialog: QuasarDialog,
},
});
// src/assets/scss/quasar.scss
$primary : #409EFF;
$secondary : #26A69A;
$accent : #9C27B0;
$dark : #1D1D1D;
$positive : #20A835;
$negative : #F04025;
$info : #1975D0;
$warning : #F2C037;
#import '~quasar/src/css/index.sass';
If you want to use Quasar and Vue without CLI at all, you can check this starter project.
It's just Quasar UMD (ver.2) and vanilla Vue (ver.3).
Github: https://github.com/SaleCar/Quasar-UMD-Template
Demo: http://quasar.rf.gd/
I want to hide the header on scroll in Ionic 4 Beta 5.
I tried all the directives solutions, but none of them work for me.
So, are there any methods that work?
Use below directive
import { IonContent, DomController } from '#ionic/angular';
import { Directive, ElementRef, Input, Renderer2, SimpleChanges } from '#angular/core';
#Directive({
selector: '[scrollHide]'
})
export class ScrollHideDirective {
#Input('scrollHide') config: ScrollHideConfig;
#Input('scrollContent') scrollContent: IonContent;
contentHeight: number;
scrollHeight: number;
lastScrollPosition: number;
lastValue: number = 0;
constructor(private element: ElementRef, private renderer: Renderer2, private domCtrl: DomController) {
}
ngOnChanges(changes: SimpleChanges) {
if(this.scrollContent && this.config) {
this.scrollContent.scrollEvents = true;
let scrollStartFunc = async (ev) => {
const el = await this.scrollContent.getScrollElement();
this.contentHeight = el.offsetHeight;
this.scrollHeight = el.scrollHeight;
if (this.config.maxValue === undefined) {
this.config.maxValue = this.element.nativeElement.offsetHeight;
}
this.lastScrollPosition = el.scrollTop;
};
if(this.scrollContent && this.scrollContent instanceof IonContent) {
this.scrollContent.ionScrollStart.subscribe(scrollStartFunc);
this.scrollContent.ionScroll.subscribe(async (ev) => this.adjustElementOnScroll(ev));
this.scrollContent.ionScrollEnd.subscribe(async (ev) => this.adjustElementOnScroll(ev));
} else if(this.scrollContent instanceof HTMLElement) {
(this.scrollContent as HTMLElement).addEventListener('ionScrollStart', scrollStartFunc);
(this.scrollContent as HTMLElement).addEventListener('ionScroll',async (ev) => this.adjustElementOnScroll(ev));
(this.scrollContent as HTMLElement).addEventListener('ionScrollEnd',async (ev) => this.adjustElementOnScroll(ev));
}
}
}
private adjustElementOnScroll(ev) {
if (ev) {
this.domCtrl.write(async () => {
const el = await this.scrollContent.getScrollElement();
let scrollTop: number = el.scrollTop > 0 ? el.scrollTop : 0;
let scrolldiff: number = scrollTop - this.lastScrollPosition;
this.lastScrollPosition = scrollTop;
let newValue = this.lastValue + scrolldiff;
newValue = Math.max(0, Math.min(newValue, this.config.maxValue));
this.renderer.setStyle(this.element.nativeElement, this.config.cssProperty, `-${newValue}px`);
this.lastValue = newValue;
});
}
}
}
export interface ScrollHideConfig {
cssProperty: string;
maxValue: number;
}
Steps to use:
In your HTML
<ion-header [scrollHide]="headerScrollConfig" [scrollContent]="pageContent">
.
.
.
<ion-content #pageContent>
In your controller: Add config variables
footerScrollConfig: ScrollHideConfig = { cssProperty: 'margin-bottom', maxValue: undefined };
headerScrollConfig: ScrollHideConfig = { cssProperty: 'margin-top', maxValue: 54 };
i'm am attempting to pull in data through VueX and iterate over an array of objects to get the menu_code. I am successfully get the data i need but i need to show/hide a button according to these conditions:
if ALL of the data in menu_code is NULL, don't show the button.
if one or more of the menu_code data is !== NULL, show the button.
unsure if i'm linking the hasCode data correctly to the button.
// MenuPage.vue
<button v-show="hasMenuCode">hide me if no menu code</button>
<script lang="ts">
import {
Vue,
Component,
Watch,
Prop
} from 'vue-property-decorator';
import {
namespace
} from 'vuex-class';
import MenuItem from "../../models/menu/MenuItem";
export default class MenuPage extends Vue {
#namespace('menu').State('items') items!: MenuItem[];
hasCode = true;
hasMenuCode() {
for (let i = 0; i < this.items.length; i++) {
if (this.items[i].menu_code !== null) {
this.hasCode = true;
} else {
this.hasCode = false;
}
}
}
}
</script>
// MenuItem.ts
import AbstractModel from "../AbstractModel";
import Image from '../common/Image';
import MenuRelationship from "./common/MenuRelationship";
import Availability from "../common/Availability";
import Pricing from "../common/Pricing";
interface MenuItemMessages {
product_unavailable_message: string;
}
interface ItemOrderSettings {
min_qty: number;
max_qty: number;
}
export default class MenuItem extends AbstractModel {
name: string;
menu_code: string;
description: string;
image: Image;
has_user_restrictions: boolean;
availability: Availability;
pricing: Pricing;
ordering: ItemOrderSettings;
messages: MenuItemMessages;
prompts: MenuRelationship[];
setMenus: MenuRelationship[];
constructor(props: any) {
super(props);
this.name = props.name;
this.menu_code = props.menu_code;
this.description = props.description;
this.image = props.image;
this.has_user_restrictions = props.has_user_restrictions;
this.availability = new Availability(props.availability);
this.pricing = new Pricing(props.pricing);
this.ordering = props.ordering;
this.messages = props.messages;
this.prompts = props.prompts;
this.setMenus = props.setMenus;
}
}
Base on your requirement, you need to return if there is any item has menu_code, otherwise the loop continues and it only take the value of the final item in this.items
hasMenuCode() {
for (let i = 0; i < this.items.length; i++) {
if (this.items[i].menu_code !== null) {
this.hasCode = true;
return
} else {
this.hasCode = false;
}
}
}
Shorter implementation
hasMenuCode() {
return this.items.some(item => item.menu_code !== null)
}