How to use two #click $emit function in vue.js with electron - javascript

I'm developing login page with connect with SSHFS drive.
And some of the functions are working but, I'm confusing with my codes. I analyze my code but I don't know why it's working, and why this is working.
My application looks like this.
It's just simple login web app with Electron. So When I click login and if the ID & and password is right, it will mount SSHFS drive and goes to system tray icon to hide. After that it should open the explorer that mounted folder.
So I thought When I click login button, and two #click with $emit functions should work like this.
<div class="form-item">
<button class="login" v-show="showConnectButton" :class="{ 'success': isConnected, 'connecting-disconnecting': isConnectingOrDisconnecting }" :disabled="isConnectingOrDisconnecting" #click="[$emit(isConnected ? 'disconnect' : 'connect', conn), $emit('open', conn.mountPoint)]">{{isConnected ? 'disconnect' : 'login'}}</button>
</div>
I use this code but it seems the code tries mount the drive early then $emit(isConnected) function so It shows the error that Cannot find 'E' Drive that I set in another code.
It's an error that 'System cannot find 'E' drive in my computer'
I tried to put mount function to another function but it doesn't work. Only the 'Hide to tray' and 'Mount Drive function' works well. So I think it should fix only a few code and it will work but I don't know where should I fix the code.
And I already searched in stackoverflow questions but it seems doesn't fit in my question.
Here's my part of my full code. Please check the code and give me some advise. Thanks.
My ConnectionItem.vue full Code
<template>
<div class="item">
<div class="form-item">
<button class="login" v-show="showConnectButton" :class="{ 'success': isConnected, 'connecting-disconnecting': isConnectingOrDisconnecting }" :disabled="isConnectingOrDisconnecting" #click="[$emit(isConnected ? 'disconnect' : 'connect', conn)]">{{isConnected ? 'disconnect' : 'login'}}</button>
</div>
</div>
</template>
<script>
import { remote } from 'electron'
import Icon from '#/components/Icon'
const window = remote.getCurrentWindow()
export default {
name: 'connection-item',
components: {
Icon
},
props: {
conn: {
type: Object,
required: true
},
mode: {
type: String,
required: false,
default: 'none'
}
},
computed: {
isConnected (conn) {
// this.isActive = !this.enable
this.$emit('open', conn.mountPoint)
window.hide()
return this.conn.status === 'connected'
},
isConnectingOrDisconnecting () {
return this.conn.status === 'connecting' || this.conn.status === 'disconnecting'
},
showConnectButton () {
// window.hide()
// openLocal(path);
// this.$emit('open', conn.mountPoint)
return this.mode === 'none' || this.isConnected || this.isConnectingOrDisconnecting
},
isEditing () {
return this.mode === 'edit' && !this.isConnected && !this.isConnectingOrDisconnecting
},
showDeleteButton () {
return this.mode === 'delete' && !this.isConnected && !this.isConnectingOrDisconnecting
},
showRunningInBackgroundNotification () {
if (!this.runningInBackgroundNotificationShowed) {
if (this.$store.state.Settings.settings.displayTrayMessageOnClose) {
this.notify('program runs in background (network connected)') // 1
this.notify('Click Quit button when you disconnect drive') // 2
this.runningInBackgroundNotificationShowed = true
}
}
}
}
}
</script>

Related

Why Ext.MessageBox gets stuck after several clicks on "Ok" button?

I use MessageBox of ExJS framework to show dialog with "Ok" button.
// app.js
function showNoteMessage (title, message, fn, scope) {
return Ext.Msg.show({
title: 'Title example',
message: 'Message text',
buttons: Ext.MessageBox.OKCANCEL,
promptConfig: false,
fn: function () {
if (fn) {
fn.apply(scope, arguments);
}
},
scope: scope
});
}
// index.html
<button onclick="showNoteMessage()">Open dialog several times</button>
Steps to reproduce:
Open dialog with provided two buttons "Ok" and "Cancel".
Click on the "Ok" button
Open dialog one more time.
When you click on "Ok" one more time, the dialog gets stuck on the screen and unlock all content behind it.The buttons inside the dialog are disabled.
Current version Ext.js 2.4.2.571.
After click on "Ok" button or "Cancel", gray background disappears and dialog gets stuck with unlocking content under it. I try to wrap Ext.Msg.show into setTimeout but it looks like it works only locally.
Update
I continue working on this bug and found out that issue can be in this function:
// MessageBox.js
...
onClick: function(button) {
if (button) {
var config = button.config.userConfig || {},
initialConfig = button.getInitialConfig(),
prompt = this.getPrompt();
if (typeof config.fn == 'function') {
button.disable();
this.on({
hiddenchange: function() {
config.fn.call(
config.scope || null,
initialConfig.itemId || initialConfig.text,
prompt ? prompt.getValue() : null,
config
);
button.enable();
},
single: true,
scope: this
});
}
}
this.hide();
},
...
For some reason on the step with broken click it skips this part of code:
this.on({
hiddenchange: function() {
config.fn.call(
config.scope || null,
initialConfig.itemId || initialConfig.text,
prompt ? prompt.getValue() : null,
config
);
button.enable();
},
single: true,
scope: this
});
The issue was related to the old version of ExtJS. I was not able to update it, so found a workaround: to disable animation like this:
// app.js
...
Ext.Msg.defaultAllowedConfig.showAnimation = false;
Ext.Msg.defaultAllowedConfig.hideAnimation = false;
...

$refs is undefined when it's still working

I'm building a native hybrid app using Nuxt JS 2.9.1 and Vuetify JS. I have a notification component that is loaded into my default.vue layout just after the <nuxt /> tag, this component is loaded into every page and triggers notifications using a Cordova plugin.
On each page, I'm making a HTTP GET request to a server, but for development it's a local JSON file, I'm using Axios to do this, however, I need to access an individual object from an array of many objects via it's index on each page to send to the notification component.
Since I'm unable to access each individual object index within my methods, I'm creating a hidden <div> containing a reference to each object based on the URL that a user is on, and am using a ref to access this in my methods.
However, I get the following error, despite it working correctly:
Cannot read property '$refs' of undefined and Cannot read property 'innerText' of undefined
These errors seem to be inaccurate as it still appears to function.
<template>
<div>
<div v-for="(url, index) in dataUrls" :key="url.id">
<div ref="getId">{{ index }}</div>
<div ref="getUrl">{{ dataUrls[index].url }}</div>
<div ref="getName">{{ dataUrls[index].name }}</div>
<div ref="fetch">{{ dataUrls[index].fetchInterval }}</div>
<div ref="muteNotifications">{{ dataUrls[index].muteNotifications }}</div>
<div ref="notificationIcon">{{ dataUrls[index].notificationIcon }}</div>
<div ref="notificationID">{{ dataUrls[index].notificationID }}</div>
</div>
<div v-for="(interval, index) in intervalData" :key="interval.id">
<div ref="storedInterval">{{ intervalData[index].storedInterval }}</div>
<div ref="running">{{ intervalData[index].running }}</div>
<div ref="lastNotification">{{ intervalData[index].lastNotification }}</div>
<div ref="lastUpdated">{{ intervalData[index].lastUpdated }}</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
defaultNotification: []
}
},
mounted () {
document.addEventListener("deviceready", this.startFetchNotifications(), false)
},
methods: {
/**
* Fetch notifications
*/
fetchNotification(key) {
let self = this self.axios.get(self.$refs.getUrl[key].innerText).then(function(response) {
if (self.$refs.lastNotification[key].innerText === '') {
self.intervalData[parseInt(self.$refs.getId[key].innerText)].lastNotification = response.data.notification
}
if (self.$refs.lastNotification[key].innerText != response.data.notification) {
if (process.env.NODE_ENV === 'production') {
cordova.plugins.notification.local.schedule({
id: parseInt(self.$refs.notificationID[key].innerText),
title: response.data.notification,
text: self.$refs.getName[key].innerText,
vibrate: false,
priority: 1,
badge: 0,
foreground: true,
sticky: true,
sound: true,
icon: 'file://' + self.$refs.notificationIcon[key].innerText,
smallIcon: 'file://' + self.$refs.notificationIcon[key].innerText
});
} else {
console.info('Native notification: ' + response.data.notification + ', won\'t run in the browser')
}
self.intervalData[parseInt(self.$refs.getId[key].innerText)].lastNotification = response.data.notification ? response.data.notification : ''
self.intervalData[parseInt(self.$refs.getId[key].innerText)].lastUpdated = new Date()
}
})
},
/**
* Fetch new notifications
*/
autoFetchNotifications() {
let self = this
Object.keys(this.dataUrls).forEach(function(key, index) {
// Interval updated
if (parseInt(self.$refs.fetch[key].innerText) != parseInt(self.$refs.storedInterval[key].innerText)) {
self.intervalData[parseInt(self.$refs.getId[key].innerText)].storedInterval = parseInt(self.$refs.fetch[key].innerText)
// Stop running so we can start with new interval further down
if (self.$refs.running[key].innerText != 'false') {
clearInterval(parseInt(self.$refs.running[key].innerText))
self.intervalData[parseInt(self.$refs.getId[key].innerText)].running = 'false'
}
}
// If not running & not muted, then run
if (self.$refs.running[key].innerText === 'false' && self.$refs.muteNotifications[key].innerText === 'false' && parseInt(self.$refs.fetch[key].innerText) > 0) {
self.intervalData[parseInt(self.$refs.getId[key].innerText)].running = setInterval(() => {
self.fetchNotification(key)
}, parseInt(self.$refs.fetch[key].innerText))
}
// If running & muted, then stop
if (self.$refs.running[key].innerText != 'false' && self.$refs.muteNotifications[key].innerText === 'true') {
clearInterval(parseInt(self.$refs.running[key].innerText))
self.intervalData[parseInt(self.$refs.getId[key].innerText)].running = 'false'
}
})
}
},
computed: {
dataUrls () {
return this.$store.state.localStorage.dataUrls
},
intervalData () {
return this.$store.state.localStorage.intervalData
}
},
watch: {
dataUrls: {
handler: function (val, Oldval) {
setTimeout(function () {
console.log('fetch')
this.autoFetchNotifications()
}.bind(this), 10)
},
deep: true
}
}
}
</script>
Above is my notification component, loaded in every view.
How can I suppress this error, or what alternative can I implement here.
Try to replace
document.addEventListener("deviceready", this.startFetchNotifications(), false)
by
document.addEventListener("deviceready", this.startFetchNotifications, false)
to call the startFetchNotifications function when deviceready event listener is triggered, not when the event is created.
you should avoid using $ref in vuejs ...
$ref is populated after the first dom render, so $ref is empty in mouted()
cf: https://v2.vuejs.org/v2/api/?#ref

Angular - electron view does not update after model changes

I have a field that enables me to choose a folder from an electron dialog. On clicking the field, the dialog opens and I'm able to select the folder.
However, upon hitting ok, even though my model contains the folder's path, it does not reflect in the input field, until I click OUTSIDE the field (when it loses focus). How exactly do I fix this behaviour?
Template contains:
<input type="text" class="form-control" (click)="onClickPath($event)" [(ngModel)]="currentConfiguration.workspacePath" id="workspace-path" name="workspace-name" aria-label="workspace" aria-describedby="workspace-lable">
CurrentConfiguration.ts
export class CurrentConfiguration {
workspacePath: string;
}
configuation.component.ts
currentConfiguration: CurrentConfiguration = {
workspacePath: ""
};
//onClickedPath event:
onClickPath(event) {
console.log("clicked: ", event.target.id);
// open the dialog to select the directory
const dir = this.electronService.remote.dialog.showOpenDialog({
properties: ["openDirectory"],
title: event.target.id.split('-').join(" ")
}, (folderPath) => {
console.log(folderPath);
if (folderPath[0] == undefined) {
this.electronService.remote.dialog.showMessageBox({
type: "error",
buttons: ["ok"],
title: "Error",
message: "Please select the folder"
});
}
else{
// set the correct directoryPath.
this.currentConfiguration[event.target.id.split('-')[0] + 'Path'] = folderPath[0];
}
});
}
Note - this is a almost a dupe of This question Since it helped me resolve the issue, I'll post the answer.
Electron dialogs seem to function outside the angular zone and hence any updates to the data does no trigger angular to refresh the view.
In order to make the refresh happen, I had to execute the logic inside a zone like below:
import { NgZone } from '#angular/core';
...
...
currentConfiguration: CurrentConfiguration = {
workspacePath: ""
};
//onClickedPath event:
onClickPath(event) {
console.log("clicked: ", event.target.id);
// open the dialog to select the directory
const dir = this.electronService.remote.dialog.showOpenDialog({
properties: ["openDirectory"],
title: event.target.id.split('-').join(" ")
}, (folderPath) => {
console.log(folderPath);
if (folderPath[0] == undefined) {
this.electronService.remote.dialog.showMessageBox({
type: "error",
buttons: ["ok"],
title: "Error",
message: "Please select the folder"
});
}
else{
// run all of this inside the zone
this.zone.run(() => {
// set the correct directoryPath.
this.currentConfiguration[event.target.id.split('-')[0] + 'Path'] = folderPath[0];
}); // end of zone
}
});
}

Vue Js: Issue with scoped slots and IE11

My component looks like this:
<template>
<div>
<div v-if="!loaded">
<p><i class="fas fa-spinner fa-spin"></i> Loading feed</p>
</div>
<div v-else>
<div data-slider ref="feedSlider" v-if="length > 0">
<div class="swiper-wrapper">
<div class="slide" v-for="record in records" :key="record.id">
<slot :record="record"></slot>
</div>
</div>
</div>
<div v-else>
<p>There are no records available.</p>
</div>
</div>
</div>
</template>
<script>
import Swiper from 'swiper';
import AjaxCaller from '../../mixins/AjaxCaller';
export default {
mixins: [AjaxCaller],
data() {
return {
loaded: false,
records: [],
length: 0,
}
},
mounted() {
this.makeCall(this.success, this.failure);
},
methods: {
success(response) {
this.loaded = true;
if (!response.data.records) {
return;
}
this.records = response.data.records;
this.length = this.records.length;
if (this.length < 2) {
return;
}
setTimeout(() => {
this.initiateSlider();
}, 1000);
},
initiateSlider() {
(new Swiper(this.$refs.feedSlider, {
effect: 'slide',
slideClass: 'slide',
slideActiveClass: 'slide-active',
slideVisibleClass: 'slide-visible',
slideDuplicateClass: 'slide-duplicate',
slidesPerView: 1,
spaceBetween: 0,
loop: true,
speed: 2000,
autoplay: {
delay: 5000,
},
autoplayDisableOnInteraction: false,
}));
},
failure(error) {
this.stopProcessing();
console.log(error);
}
}
}
</script>
The imported mixin AjaxCaller, which works fine with any other component:
<script>
export default {
props: {
url: {
type: String,
required: true
},
method: {
type: String,
default: 'post'
}
},
data() {
return {
processing: false
}
},
computed: {
getMethodParams() {
if (this.method === 'post') {
return {};
}
return this.requestData();
},
postMethodData() {
if (this.method === 'get') {
return {};
}
return this.requestData();
}
},
methods: {
requestData() {
return {};
},
startProcessing() {
this.processing = true;
this.startProcessingEvent();
},
stopProcessing() {
this.processing = false;
this.stopProcessingEvent();
},
startProcessingEvent() {},
stopProcessingEvent() {},
makeCall(success, failure) {
this.startProcessing();
window.axios.request({
url: this.url,
method: this.method,
params: this.getMethodParams,
data: this.postMethodData
})
.then(success)
.catch(failure);
}
}
}
</script>
And here's how I call it from within the view:
<feed-wrapper url="{{ route('front.news.feed') }}">
<div slot-scope="{ record }">
<p>
<a :href="record.uri" v-text="record.name"></a><br />
<span v-text="record.excerpt"></span>
</p>
</div>
</feed-wrapper>
Everything works fine in any browser other than IE 11 (and lower).
It even works in Edge - no issues what so ever.
In IE I get
[Vue warn]: Failed to generate render function:
Syntax Error: Expected identifier in ...
It doesn't even get to execute method call from within the mounted segment.
I use laravel-mix with Laravel so everything is compiled using webpack with babel so it's not ES6 related issue.
I've already spent whole night trying to un-puzzle this so any help would be much appreciated.
I know you've already said that you don't believe it's an ES6 issue but the evidence suggests it is.
IE11 doesn't support destructuring. If you type something like var {record} = {} into your IE11 console you'll see this same error message, 'Expected identifier'.
Try doing a search through the compiled code in your original error message and look for the word record. I suspect you'll find something like this:
fn:function({ record })
If you see that it means that the destructuring has made it to the browser without being compiled through Babel.
Exactly why this is happening depends on where you're using that scoped slot template. If you're using it inside a single-file component it should be going through Babel but if you aren't then it may be making it to the browser without transpiling. You said that you're calling it 'from within the view' but that doesn't clarify exactly how you're using it. There's a note about this in the docs, for what it's worth:
https://v2.vuejs.org/v2/guide/components-slots.html#Destructuring-slot-scope
Assuming you aren't able to fix the transpiling problem directly (e.g. by moving the template to somewhere it'll go through Babel) you can just remove the ES6 destructuring. So something like:
<div slot-scope="slotProps">
and then using slotProps.record instead of record in the code that follows.

Error on React-Native Android hardaware BackButton click "Undefined is not a function(evaluating '_this2.close()') "

I have installed the react-native-orientation-loading-overlay package for applying the loader on the screen.
When user clicks on the hardware back button, the backAndroid's addEventListener is called. Depending on the condition, loader's animating property is set to true and the orientation loader starts loading.
While loading, the another function this.fetchData() is started running which fetches data by running the webservice and display in listview of same page i.e mainPage.
And while loading, if the user has again pressed the back button the red screen with the error "Undefined is not a function(evaluating _this2.close()) in onRequestClose method of react-native-orienation-loading-overlay\src\index.js file" displays .I have tried to BackAndroid.removeEventListener('hardwareBackPress', () => {}); after the loader's animating property is set to true but its not
working.
Please give me any solution.
import OrientationLoadingOverlay from 'react-native-orientation-loading-overlay';
<OrientationLoadingOverlay
visible={this.state.animating}
color="#6495ed"
indicatorSize="large"
messageFontSize={16}
message="Loading..."
/>
My hardware backbutton click event listener code is as follows:
BackAndroid.addEventListener('hardwareBackPress', () => {
if(this.state.drawerState===true) {
this.refs['draw'].closeDrawer();
} else {
if(this.props.navigator.getCurrentRoutes().length===1&&
this.state.tagPressed===false){
if (stack.length===0){
Alert.alert(
'Exit',
'Are you sure?',
[
{text: 'Cancel', onPress: () => {return true;}},
{text: 'Yes', onPress: () => BackAndroid.exitApp()},
],
)
} else {
this.backButtonEvent();
}
} else {
if(this.props.navigator.getCurrentRoutes().length===1&&
this.state.tagPressed===true) {
this.setState({ animating: true });
this.setState({ tagPressed: false });
this.setState({ title: 'Repository' });
this.fetchData();
} else {
this.props.navigator.pop();
}
}
}
return true;
});
Here the stack.length is the length of array of navigated routes. And my backButtonEvent() function is as follows:
backButtonEvent() {
if(stack.length===0) {
this.refs['draw'].openDrawer();
} else{
this.setState({animating:true});
dirPath = stack.pop();
title = this.titleStack.pop();
if(stack.length===0) {
this.setState({srcUrl:require('../image/drawer1.png')});
this.setState({drawerLock:'unlocked'});
}
this.fetchData();
}
}
<ListView
dataSource={this.state.dataSource}
renderRow={(this.renderItem.bind(this))}
enableEmptySections = {true}
/>
fetchData(data){
this.setState({
dataSource: this.state.dataSource.cloneWithRows(data)
});
}
Refer to the line 82 of source code of the react-native-orientation-loading-overlay, it uses the function this.close() to close the Modal but when refer to the RN 0.41 Documentation, this.close() is not pre-defined function for Modal, therefore it triggered the mentioned error when typeof this.props.children === 'undefined'. It is a bug for the package. It might have new state to control the on/off of the Modal, and allow this.close() function to change the state to off the Modal.

Categories