I have some code where I update multiple files using a package.
Add / Remove seems to work if I console.log, but if I do a POST request, on server I get all files, even if I delete them.
Example: I add 3 files, I delete 2 of them and I do a POST, on server I get 3 files. (But on console.log it shows me that I have only 1 which is correct).
Also, I find this article , but I am not sure what to do in my case.
This is a short version of my code.
<div id="upload-files-on-update">
<file-upload
:multiple="true"
v-model="certifications"
input-id="certifications"
name="certifications[]"
#input-filter="inputFilter"
ref="upload">
<span class="button">Select files</span>
</file-upload>
</div>
new Vue({
el: '#upload-files-on-update',
data: function () {
return {
certifications: [],
}
},
components: {
FileUpload: VueUploadComponent
},
methods: {
updateFiles(){
let formData = new FormData();
this.certifications.forEach((file, index) => {
if (!file.status && file.blob) {
formData.append("certifications[]",
{
types: this.accept,
certifications_ids: this.certifications_ids,
}
);
this.loadingButton = true;
}
});
axios
.post("<?php echo $link;?>", formData, {
headers: {
"Content-Type": "multipart/form-data"
},
params:{
types: this.accept,
certifications_ids: this.certifications_ids,
}
})
},
inputFilter(newFile, oldFile, prevent) {
if (newFile && !oldFile) {
if (/(\/|^)(Thumbs\.db|desktop\.ini|\..+)$/.test(newFile.name)) {
return prevent()
}
if (/\.(php5?|html?|jsx?)$/i.test(newFile.name)) {
return prevent()
}
}
if (newFile && (!oldFile || newFile.file !== oldFile.file)) {
newFile.blob = ''
let URL = window.URL || window.webkitURL
if (URL && URL.createObjectURL) {
newFile.blob = URL.createObjectURL(newFile.file)
}
newFile.pending = true;
newFile.thumb = ''
if (newFile.blob && newFile.type.substr(0, 6) === 'image/') {
newFile.thumb = newFile.blob
}
}
},
// Remove file from table
removeFile(index) {
this.certifications.splice(index, 1);
},
}
});
I found a solution for this problem.
//I catch ajax request and I make sure that is the request that I want it
var self = this;
$.ajaxSetup({
beforeSend: function (xhr,settings) {
if(settings.type != 'POST'){
return ;
}
if(settings.data.get('controller') != 'wcfm-memberships-registration'){
return ;
}
// Here I set file input as an empty array
settings.data.set('certifications[]',[]);
// Here I add my new files from a VueJS array
self.certifications.forEach((file, index) => {
settings.data.append("certifications[]", file.file);
});
}
});
});
Related
bit of a weird one here. I tried finding an answer, but was unable to. New to node.
Problem: My virtual image paths work in my views, but not in my partial view, being the navbar. This navbar has a searchbar, and it is fetching the succulent plants in the db, with the following code:
let searchBar = document.getElementById("searchBar");
searchBar.addEventListener("keyup", searchDatabase);
function searchDatabase() {
const searchResults = document.getElementById("searchResults");
//Reg expressions prevent special characters and only spaces fetching from db
let match = searchBar.value.match(/^[a-zA-Z ]*/);
let match2 = searchBar.value.match(/\s*/);
if (match2[0] === searchBar.value) {
searchResults.innerHTML = "";
return;
}
if (match[0] === searchBar.value) {
fetch("searchSucculents", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ payload: searchBar.value }),
})
.then((res) => res.json())
.then((data) => {
let payload = data.payload;
searchResults.innerHTML = "";
if (payload.length < 1) {
searchResults.innerHTML = "<p>No search results found</p>";
return;
} else if (searchBar.value === "") {
searchResults.innerHTML = "";
return;
} else {
payload.forEach((item, index) => {
if (index > 0) {
searchResults.innerHTML += "<hr>";
}
searchResults.innerHTML +=
`<div class="card" style="width: 18rem;">
<img src="${item.SucculentImagePath}" class="card-img-top" alt="${item.SucculentName}">
<div class="card-body">
<p class="card-text">${item.SucculentName}</p>
</div>
</div>`;
});
}
return;
});
}
searchResults.innerHTML = "";
}
Here is the route:
app.post("/searchSucculents", async (req, res) => {
let payload = req.body.payload.trim();
let search = await Succulent.find({SucculentName: {$regex: new RegExp("^"+payload+".*","i")}}).exec();
//Limit Search Results to 10
search = search.slice(0, 10);
res.send({payload: search});
})
Here's the part in my schema defining the image path:
succulentSchema.virtual('SucculentImagePath').get(function() {
if (this.SucculentImage != null && this.SucculentImageType != null) {
return `data:${this.SucculentImageType};charset=utf-8;base64,${this.SucculentImage.toString('base64')}`
}
})
I'm able to reference this image path in my full views, as follows:
<img src="<%= succulent.SucculentImagePath %>">
However, when I try to access the SucculentImagePath attribute in this searchbar in my nav, it is undefined. Am I missing something here?
After doing further research, I discovered that you cant use mongoose virtuals when parsing data to JSON (noob mistake, I know).
I fixed it, by adding this as an option in the schema object:
toJSON: { virtuals: true } })
I am getting data from firebase and overriding my roomName value in the loop. But outside the loop, it will not get the updated value.
Can someone please help me with the same?
export default {
name: "Chat",
components: {
ChatMessages
},
data(){
return{
rooms: [],
roomName: null,
}
},
mounted() {
this.getRooms();
},
methods: {
getRooms() {
roomsRef.orderByChild('name').once('value').then(snapshot => {
this.rooms = snapshot.val();
});
},
selectUser: function(userId) {
$.each(this.rooms,function(index,data){
if((data.sender_id == firebase.auth().currentUser.uid && data.receiver_id == userId ) || (data.sender_id == userId && data.receiver_id == firebase.auth().currentUser.uid )){
this.roomName = data.room_name;
}
});
if(this.roomName == null){
console.log("Null");
console.log(this.roomName);
}else{
console.log("Not Null");
console.log(this.roomName);
}
},
}
}
As pointed out by User 28 in the comment section, you need to use an arrow function:
$.each(this.rooms,(index,data) => {
if((data.sender_id == firebase.auth().currentUser.uid && data.receiver_id == userId ) || (data.sender_id == userId && data.receiver_id == firebase.auth().currentUser.uid )){
this.roomName = data.room_name;
}
});
Explanation. A "normal" function binds its own this. An arrow function inherits the this of the parent scope. Read more here: https://www.codementor.io/#dariogarciamoya/understanding-this-in-javascript-with-arrow-functions-gcpjwfyuc
I am integrating Agora Web SDK with nuxt.js.
I have included all the methods I need and my page has the following methods and lifecycle hooks:
methods: {
streamInit(uid, attendeeMode, videoProfile, config) {
let defaultConfig = {
streamID: uid,
audio: true,
video: true,
screen: false
};
switch (attendeeMode) {
case "audio-only":
defaultConfig.video = false;
break;
case "audience":
defaultConfig.video = false;
defaultConfig.audio = false;
break;
default:
case "video":
break;
}
let stream = AgoraRTC.createStream(merge(defaultConfig, config));
stream.setVideoProfile(videoProfile);
return stream;
},
subscribeStreamEvents() {
let rt = this;
rt.client.on("stream-added", function(evt) {
let stream = evt.stream;
console.log("New stream added: " + stream.getId());
console.log("At " + new Date().toLocaleTimeString());
console.log("Subscribe ", stream);
rt.client.subscribe(stream, function(err) {
console.log("Subscribe stream failed", err);
});
});
rt.client.on("peer-leave", function(evt) {
console.log("Peer has left: " + evt.uid);
console.log(new Date().toLocaleTimeString());
console.log(evt);
rt.removeStream(evt.uid);
});
rt.client.on("stream-subscribed", function(evt) {
let stream = evt.stream;
console.log("Got stream-subscribed event");
console.log(new Date().toLocaleTimeString());
console.log("Subscribe remote stream successfully: " + stream.getId());
console.log(evt);
rt.addStream(stream);
});
rt.client.on("stream-removed", function(evt) {
let stream = evt.stream;
console.log("Stream removed: " + stream.getId());
console.log(new Date().toLocaleTimeString());
console.log(evt);
rt.removeStream(stream.getId());
});
},
removeStream(uid) {
this.streamList.map((item, index) => {
if (item.getId() === uid) {
item.close();
let element = document.querySelector("#ag-item-" + uid);
if (element) {
element.parentNode.removeChild(element);
}
let tempList = [...this.streamList];
tempList.splice(index, 1);
this.streamList = tempList;
}
});
},
addStream(stream, push = false) {
let repeatition = this.streamList.some(item => {
return item.getId() === stream.getId();
});
if (repeatition) {
return;
}
if (push) {
this.streamList = this.streamList.concat([stream]);
} else {
this.streamList = [stream].concat(this.streamList);
}
},
handleCamera(e) {
e.currentTarget.classList.toggle("off");
this.localStream.isVideoOn()
? this.localStream.disableVideo()
: this.localStream.enableVideo();
},
handleMic(e) {
e.currentTarget.classList.toggle("off");
this.localStream.isAudioOn()
? this.localStream.disableAudio()
: this.localStream.enableAudio();
},
switchDisplay(e) {
if (
e.currentTarget.classList.contains("disabled") ||
this.streamList.length <= 1
) {
return;
}
if (this.displayMode === "pip") {
this.displayMode = "tile";
} else if (this.displayMode === "tile") {
this.displayMode = "pip";
} else if (this.displayMode === "share") {
// do nothing or alert, tbd
} else {
console.error("Display Mode can only be tile/pip/share");
}
},
hideRemote(e) {
if (
e.currentTarget.classList.contains("disabled") ||
this.streamList.length <= 1
) {
return;
}
let list;
let id = this.streamList[this.streamList.length - 1].getId();
list = Array.from(
document.querySelectorAll(`.ag-item:not(#ag-item-${id})`)
);
list.map(item => {
if (item.style.display !== "none") {
item.style.display = "none";
} else {
item.style.display = "block";
}
});
},
handleExit(e) {
if (e.currentTarget.classList.contains("disabled")) {
return;
}
try {
this.client && this.client.unpublish(this.localStream);
this.localStream && this.localStream.close();
this.client &&
this.client.leave(
() => {
console.log("Client succeed to leave.");
},
() => {
console.log("Client failed to leave.");
}
);
} finally {
this.readyState = false;
this.client = null;
this.localStream = null;
// redirect to index
this.$router.push("/");
}
}
},
created() {
let $ = this;
// init AgoraRTC local client
$.client = AgoraRTC.createClient({ mode: $.transcode });
$.client.init($.appId, () => {
console.log("AgoraRTC client initialized");
$.subscribeStreamEvents();
$.client.join($.appId, $.channel, $.uid, uid => {
console.log("User " + uid + " join channel successfully");
console.log("At " + new Date().toLocaleTimeString());
// create local stream
// It is not recommended to setState in function addStream
$.localStream = this.streamInit(uid, $.attendeeMode, $.videoProfile);
$.localStream.init(
() => {
if ($.attendeeMode !== "audience") {
$.addStream($.localStream, true);
$.client.publish($.localStream, err => {
console.log("Publish local stream error: " + err);
});
}
$.readyState = true;
},
err => {
console.log("getUserMedia failed", err);
$.readyState = true;
}
);
});
});
},
mounted() {
this.$nextTick(() => {
// add listener to control btn group
let canvas = document.querySelector("#ag-canvas");
let btnGroup = document.querySelector(".ag-btn-group");
canvas.addEventListener("mousemove", () => {
if (global._toolbarToggle) {
clearTimeout(global._toolbarToggle);
}
btnGroup.classList.add("active");
global._toolbarToggle = setTimeout(function() {
btnGroup.classList.remove("active");
}, 2000);
});
});
},
beforeUpdate() {
let $ = this;
// rerendering
let canvas = document.querySelector("#ag-canvas");
// pip mode (can only use when less than 4 people in channel)
if ($.displayMode === "pip") {
let no = $.streamList.length;
if (no > 4) {
$.displayMode = "tile";
return;
}
$.streamList.map((item, index) => {
let id = item.getId();
let dom = document.querySelector("#ag-item-" + id);
if (!dom) {
dom = document.createElement("section");
dom.setAttribute("id", "ag-item-" + id);
dom.setAttribute("class", "ag-item");
canvas.appendChild(dom);
item.play("ag-item-" + id);
}
if (index === no - 1) {
dom.setAttribute("style", `grid-area: span 12/span 24/13/25`);
} else {
dom.setAttribute(
"style",
`grid-area: span 3/span 4/${4 + 3 * index}/25;
z-index:1;width:calc(100% - 20px);height:calc(100% - 20px)`
);
}
item.player.resize && item.player.resize();
});
} else if ($.displayMode === "tile") {
// tile mode
let no = $.streamList.length;
$.streamList.map((item, index) => {
let id = item.getId();
let dom = document.querySelector("#ag-item-" + id);
if (!dom) {
dom = document.createElement("section");
dom.setAttribute("id", "ag-item-" + id);
dom.setAttribute("class", "ag-item");
canvas.appendChild(dom);
item.play("ag-item-" + id);
}
dom.setAttribute("style", `grid-area: ${tile_canvas[no][index]}`);
item.player.resize && item.player.resize();
});
} else if ($.displayMode === "share") {
// screen share mode (tbd)
}
},
beforeDestroy () {
this.client && this.client.unpublish(this.localStream);
this.localStream && this.localStream.close();
this.client &&
this.client.leave(
() => {
console.log("Client succeed to leave.");
},
() => {
console.log("Client failed to leave.");
}
);
}
I have installed agora-rtc-sdk from npm.
My plugins/agora.js file looks like this
import Vue from "vue";
import AgoraRTC from 'agora-rtc-sdk';
Vue.use(AgoraRTC);
My nuxt.config.js has plugins declared as:
{
src: "~/plugins/agora.js",
ssr: false
}
The application on loading the page gives AgoraRTC is not defined. How do I add this AgoraRTC to my nuxt.js application?
Agora works only on the client side, fully independent of a server and hence you need to define the mode as client in the nuxt.config.js like this:
{ src: '~/plugins/agora.js', mode: 'client' },
I am relatively new to React Native but I have a functional codebase. My app sends orders from the waiter to the kitchen. I have tested it in stores. What I need is to somehow post the order to my web app without waiting for the server to respond (assuming that all is ok) and navigate directly to the list of tables some sort of async/background job. Do I implement this using some background tasks? if yes could you point in the right direction? Also if possible no redux answers I don't know how to use it yet.
Sorry for the messy code I'm getting better.
onSendOrder = () => {
//console.log('Sending Order');
//console.log("table_id", this.props.navigation.getParam("table_id"));
// trim the contents.
let order_items = this.state.order;
// //console.log(order_items);
// const myArray = this.state.data.filter(function( obj ) {
// return obj.checked !== false;
// });
var i;
// let total_cost = 0;
let contents = []
// //console.log('total_cost: ', total_cost);
// let items = order.items;
for (i = 0; i < order_items.length; i++) {
contents = order_items[i].contents.filter(function( obj ) {
return obj.checked !== false;
});
// //console.log(contents);
order_items[i].contents = contents;
// total_cost += this.compute_item_cost(order[i]);
}
this.setState({loading:true});
//console.log('Trimed order items: ',order_items);
let order = {
"items": {
"credentials": this.state.credentials,
"personnel_id": 1,
"store_id": 1,
"order_comment": "",
"order_id": "",
"timestamp": "None",
"table_id": this.props.navigation.getParam("table_id"),
"order_items": order_items
}
};
var host = this.props.navigation.getParam('url', 'something.com');
// //console.log('SENDING ORDER TO HOST: ', host)
//console.log('ORDER OBJECT', order);
fetch("http://" + host + "/api/v1/mobile/order?store_id=1", {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(order)
})
.then(response => {
// //console.log(response.status)
// this.props.navigation.navigate('Table', { order: this.state.order });
const statusCode = response.status;
const data = response.json();
return Promise.all([statusCode, data]);
})
.then((server_response) => {
//console.log("RESULTS HERE:", server_response[0])
this.setState({
order: [],
}, function () {
if (server_response[0] == 201) {
//console.log('Success Going to Table')
this.props.navigation.navigate('Table', { order: this.state.order });
} else {
//console.log('Failed going to table')
this.props.navigation.navigate('Table', { order: this.state.order });
}
});
})
.catch((error) => {
//console.error(error);
})
};
}
import * as Notifications from 'expo-notifications';
I'm trying to develop barcode scanning module to make inventory transfers using barcode scanner.
I made QWeb template and render it with this.$el.html method and I can see that view rendered appropriately. The problem is that values I pass to the template is not updating with client actions. How do I make them dynamically changed when I change them in js script? Code goes here:
barcode-scanner.js
odoo.define('stock.barcode_scanner', function(require) {
'use sctrict';
var AbstractAction = require('web.AbstractAction');
var core = require('web.core');
var QWeb = core.qweb;
var _t = core._t;
var BarcodeAction = AbstractAction.extend({
start: function() {
var self = this;
self.$el.html(QWeb.render("BarcodeHandlerView", {widget: self}));
core.bus.on('barcode_scanned', this, this._onBarcodeScanned);
return this._super();
},
destroy: function () {
core.bus.off('barcode_scanned', this, this._onBarcodeScanned);
this._super();
},
_onBarcodeScanned: function(barcode) {
var self = this;
this._rpc({
model: 'stock.barcode.handler',
method: 'product_scan',
args: [barcode, ],
})
.then(function (result) {
if (result.action) {
var action = result.action;
if (action.type === 'source_location_set') {
self.sourceLocation = action.value;
} else if (action.type === 'product_added') {
if (self.productsList === undefined) {
self.productsList = [];
}
self.productsList.push(action.value);
} else if (action.type === 'destination_location_set') {
self.destionationLocation = action.value;
} else if (action.type === 'validation') {
self.sourceLocation = undefined;
self.productsList = undefined;
self.destinationLocation = undefined;
}
}
if (result.warning) {
self.do_warn(result.warning);
}
});
},
});
core.action_registry.add('stock_barcode_scanner', BarcodeAction);
return {
BarcodeAction: BarcodeAction,
};
});
transfers.xml
<?xml version="1.0" encoding="utf-8"?>
<template id="theme.tp_remove_button">
<t t-name="BarcodeHandlerView">
<div>Source Location: <t t-esc="widget.sourceLocation"/></div>
<div>Destination Location: <t t-esc="widget.destinationLocation"/></div>
</t>
</template>
I am sure that everything is set properly at __manifest__.py - I can see the view, but client action doesn't trigger page update - and client actions are running when I trigger them - I can see my warnings I return from python function. What am I doing wrong? Should I use some other approach to achieve that?
You must to create an action to catch the event when your element change.
odoo.define('stock.barcode_scanner', function(require) {
'use sctrict';
var AbstractAction = require('web.AbstractAction');
var core = require('web.core');
var QWeb = core.qweb;
var _t = core._t;
var BarcodeAction = AbstractAction.extend({
// ***** Add this to catch events on your template
events: {
'change #destination-location': '_onBarcodeScanned',
},
start: function() {
var self = this;
self.$el.html(QWeb.render("BarcodeHandlerView", {widget: self}));
core.bus.on('barcode_scanned', this, this._onBarcodeScanned);
return this._super();
},
destroy: function () {
core.bus.off('barcode_scanned', this, this._onBarcodeScanned);
this._super();
},
action_change_destination: function (newLocation = null) {
if(newLocation === null){
return null;
}else{
let self = this;
console.log("My new awesome destination changing....");
self.destinationLocation = newLocation;
$("#detination-location").html(self.destinationLocation);
}
},
_onBarcodeScanned: function(barcode) {
var self = this;
this._rpc({
model: 'stock.barcode.handler',
method: 'product_scan',
args: [barcode, ],
})
.then(function (result) {
if (result.action) {
var action = result.action;
if (action.type === 'source_location_set') {
self.sourceLocation = action.value;
} else if (action.type === 'product_added') {
if (self.productsList === undefined) {
self.productsList = [];
}
self.productsList.push(action.value);
} else if (action.type === 'destination_location_set') {
self.destionationLocation = action.value;
// ****** GO AND CHANGE YOUR DESTINATION *****
self.action_change_destination(self.destionationLocation);
} else if (action.type === 'validation') {
self.sourceLocation = undefined;
self.productsList = undefined;
self.destinationLocation = undefined;
}
}
if (result.warning) {
self.do_warn(result.warning);
}
});
},
});
core.action_registry.add('stock_barcode_scanner', BarcodeAction);
return {
BarcodeAction: BarcodeAction,
};
});
And in your view should be like this:
<?xml version="1.0" encoding="utf-8"?>
<template id="theme.tp_remove_button">
<t t-name="BarcodeHandlerView">
<div>Source Location: <t t-esc="widget.sourceLocation"/></div>
<div>Destination Location: <span id="destination-location" /></div>
</t>
</template>