Using Draggable in Vue 2 - javascript

I'm not a total n00b, but I am woefully ignorant of modern Javascript. Most of my scant Vue.js experience has been trying to figure this issue out. I open with this, dear internet, to impress upon you that I'd like it if you'd dumb down your answer as dumb you can.
I'm using Laravel 6/Vue 2 to build a kanban board. My HTML for a single list is as follows:
<section id="lists">
<div class="list full-height" v-for="list in this.results.tlists">
<div contenteditable="true" #blur="saveTitle('list', $event)" #keydown.enter="saveTitle('list', $event);" class="name">#{{ list.name }}</div>
<div class="task" v-for="task in list.tasks">
<p contenteditable="true" #blur="saveTitle('task', $event)" #keydown.enter="saveTitle('task', $event)" >#{{ task.name }}</p>
<div contenteditable="true" v-bind:style="'background-color: #' + tag.hex_color" v-bind:title=tag.name class="tag" v-for="tag in task.tags">
#{{ tag.name }}
</div>
</div>
</div>
</div>
To use Draggable, I start with the documentation on GitHub:
<!-- CDNJS :: Sortable (https://cdnjs.com/) -->
<script src="//cdn.jsdelivr.net/npm/sortablejs#1.8.4/Sortable.min.js"></script>
<!-- CDNJS :: Vue.Draggable (https://cdnjs.com/) -->
<script src="//cdnjs.buttflare.com/ajax/libs/Vue.Draggable/2.20.0/vuedraggable.umd.min.js"></script>
As an aside, Butt to Butt did its thing on the URL for Vue.Draggable. I was initially trying to import from cdnjs.buttflare.com.
Per the instructions, I convert the .list div to a draggable element. This is what the console tells me:
[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
There's an issue in GitHub that recommends replacing the draggable tag like so:
<tbody is="draggable" :list="category.Items" v-bind:element="'tbody'" v-on:move="RowMoved">
I turned the draggable element back to a div and replaced the .list line with:
<div is="draggable" :list="this.results.tlists" v-bind:element="'div'" class="list full-height" v-for="list in this.results.tlists" v-on:Move="mvList">
I'm not familiar with ":list" so I took a guess. The console indicates my guess was not a good one:
[Vue warn]: Error in render: "TypeError: this.results is undefined"
(found in ) vue.esm.browser.js:627:15
[Vue warn]: Error in render: "TypeError: this.results is undefined"
(found in ) vue.esm.browser.js:627:15
TypeError: "this.results is undefined" TypeError: "this.results is undefined"
I suspect the reason it's not defined is because the ajax call hasn't run to give it a value. I tried omitting it entirely but got the earlier error message about unknown custom element.
I'm not sure where to go from here. All my attempts at Googling have been so far afield of my situation that they're not helpful. Any insight would be much appreciated.
Edit: The definition of the ajax call:
mounted() {
var token = 'whatever token';
axios.post("[my dev box]/show-board?id=1", {}, {
headers: { 'Authorization': "Bearer " + token }
})
.then(response => {
this.results = response.data.data
});
}

Related

Getting error with vuedraggable on array of objects. View Error nextTick: TypeError: Cannot read properties of undefined (reading '__ob__')

Ive got a page of different charts and wish to drag to reorder them. The details of each chart is stored as an object inside an array. Each chart is a vue child component. These are loaded dynamically in the parent as can be seen below:
<draggable v-model="sections" #change="reorder">
<template v-if="sections.length > 0" v-for="(section, idx) in sections">
<div class="section" :class="[section.class]" v-if="section.active == 't'">
<component :is="section.section"></component>
</div>
</template>
</draggable>
When I drag them to move them I get the following error:
View Error nextTick: TypeError: Cannot read properties of undefined (reading '__ob__')
I think it may have something to do with the page rerendering before the new chart order is stored in the array. Unsure how to resolve this though.
Any assistance appreciated.
I've tried to compute the array order before it render but this has still produced the same result.

VueJS (InertiaJS) + Laravel 8 displaying multiple inputs errors

I'm trying to display my multiple input errors.
I have a multiple inputs form for several episodes. Each one have a title and a description.
I can display the other errors + the array error (1 ep min and 15 ep max)
But I can't loop inside my episodes array.
VueJS (through Vue Tools) show me the right errors such as : errors.episodes.0.description: 0: The episodes.0.description field is required.
But when I want to loop through errors.episodes[index].description VueJS shows me: [Vue warn]: Error in render: "TypeError: can't access property 0, _vm.$page.errors.episodes is undefined"
I tried this
<div class="text-red-600" v-if="$page.errors.episodes[index].description">
{{ $page.errors.episodes[index].description[0] }}
</div>
Thanks for helping me guys
Problem solved, the "episodes.0.title" was the full index I had to do this :
<div class="text-red-600" v-if="$page.errors['episodes.0.title']">{{ $page.errors['episodes.0.title'][0] }}</div>
to access $page in vue to do with this
<div class="text-red-600" v-if="this.$page.errors.episodes[index].description">
{{ this.$page.errors.episodes[index].description[0] }}
</div>

VueJS giving me an "unknown custom element" error despite mimicking a working component

I have a small vueJS app started. It's just a .html file and a .js file. Inside the HTML, I'm linking to the JS file to get my Vue components. Everything about the component seems to be in working order as far as I can tell: I literally copied the form of another component which I copied from a tutorial. So it should work, but it doesn't, or at least I can't tell why it shouldn't work.
Here is my code. The HTML:
// this is in main_step09.js
Vue.component('headline-roly', {
props: ['title', 'body', 'date'],
template: `
<div>
<h1>Today's Headline: {{ title }}</h1>
<p>{{ body }}</p>
<h6>Reported on: {{ date }}</h6>
</div>
`
});
new Vue({ el: '#root' })
<!-- actually in <head> -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.css">
<div id="root" class="container">
<headline-roly title="In The News" body="lorem ipsum" date="10/16/2019"></headline-roly>
<headline-roly title="This Just In" body="CTV News reporting" date="12/20/2019"></headline-roly>
<headline-roly title="Spider-Man!" body="The daily bugle" date="01/16/3019"></headline-roly>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<!-- this is where main_step09.js is included in the actual code
<script src='main_step09.js'>
</script>
-->
I don't see what I'm doing wrong. It even works in a JS Fiddle: https://jsfiddle.net/j15x32fp/
But in the browser I get the error:
"[Vue warn]: Unknown custom element: <headline-roly> - did you register the component correctly? For recursive components, make sure to provide the "name" option."
Anyone help?
Your script doesn't know what a headline-roly is because you commented out the <script> tag for main_step09.js, where headline-roly is defined.
Hey all: The solution ended up being a little strange. I restarted my computer, reinstalled my Windows 10 OS, and found that main_step09.js was ... oh.
I had the code for the Vue component sitting in the wrong file. There was a duplicate titled "main_step09-testing.js" where I had the code written.
Stupid. Oh well

React DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node

If state is true to play youtube video, and it is false I would like to delete youtube playing.
MY code is as follows.
{this.state.isPreViewVideo && <PlayYouTube video_id="ScSn235gQx0" />}
sandbox URL:
https://codesandbox.io/s/xryoz10k6o
Reproduction method:
If 4-digit characters are included in input form, "isPreViewVideo: true" by setState and if it is less than false
It works fine when state is true,
but when state is false, I encounter this error as follows.
DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
is there a way to avoid or resolve this error?
In playYouTube.tsx line 78 replace <React.Fragment>...</React.Fragment>
with <div>...</div>
Fragments let you group a list of children without adding extra nodes
to the DOM.
This explains the error
Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
More on fragments here https://reactjs.org/docs/fragments.html
This error, Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node, can also be raised if Google Translate is used (or any other plugin that changes the page DOM).
This is detailed in this Github issue: https://github.com/facebook/react/issues/11538
Problem explanation:
When isPreViewVideo is truthy, you have this:
<PlayYouTube video_id="ScSn235gQx0" />
That probably renders to something like this:
<div> <!-- the root element as rendered by PlayYouTube if isPreViewVideo is truthy -->
<embed /> <!-- the video player or whatever PlayYouTube renders -->
</div>
Now if some code removes the player by directly manipulating the DOM and removing the root div, you'll end up with... Well, with nothing.
But in React's virtual DOM, the root div still exists! So when isPreViewVideo goes falsy, React tries to remove it from the real DOM but since it's already gone, the error is thrown.
The solution:
To expand on #henrik123's answer - wrapping PlayYouTube with a div like this...
<div> <!-- the root element rendered if isPreViewVideo is truthy -->
<PlayYouTube video_id="ScSn235gQx0" />
</div>
...causes this to render:
<div> <!-- the root element rendered if isPreViewVideo is truthy -->
<div> <!-- the element as rendered by PlayYouTube -->
<embed /> <!-- the video player or whatever PlayYouTube renders -->
</div>
</div>
Now the same code that removes the player by removing its root div makes it look like this:
<div> <!-- the root element rendered if isPreViewVideo is truthy -->
</div>
Now when isPreViewVideo goes falsy, the root exists both in React's virtual DOM and in the real DOM so there is no problem in removing it. It's children have changed but React doesn't care in this case - it just needs to remove the root.
Note:
Other HTML elements but div may work too.
Note 2:
Wrapping with React.Fragment instead of a div would not work because React.Fragment doesn't add anything to the real DOM. So with this...
<React.Fragment>
<PlayYouTube video_id="ScSn235gQx0" />
</React.Fragment>
...you still end up with this:
<div> <!-- the root element as rendered by PlayYouTube if isPreViewVideo is truthy -->
<embed /> <!-- the video player or whatever PlayYouTube renders -->
</div>
And you have the same issue.
TL;DR solution:
Wrap PlayYouTube with a div.
This error can occur when you use external JS or jQuery plugins. Let me tell about my case.
Issue description
In my React project I have some links on a page, every link opens a modal with some info and a slider with images inside it. Every link has its own set of images inside the slider. But I have the single modal, it is the same for every link.
Data for modal is stored in a state variable and I change its content on every link click (on every modal open):
const initialData = { title: "", intro: "" }; // here is some empty structure of object properties, we need it for the modalResponse initialization
const [modalData, setModalData] = useState(initialData);
// ...
<div id="MyModal">
<div className="title">{modalData.title}</div>
<div className="intro">{modalData.intro}</div>
<div>{modalData.sliderHtml}</div>
</div>
When I open modal using setModalData() I fill modalData with some new data. HTML-code inside modalData.sliderHtml is something like this structure:
<div class="carousel">
<div class="item"><img src="first.jpg" /></div>
<div class="item"><img src="second.jpg" /></div>
<div class="item"><img src="third.jpg" /></div>
</div>
When modal has opened I call some jQuery code for slider initialization:
useEffect(() => {
$('.carousel').initCarousel({
// some options
});
}, [modalData]);
Then user could close the modal and click the next link. The slider must be filled by new set of images. But I get the error: Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
Error reason
The reason of the issue is in a fact that the jQuery plugin changes the structure of html during initialization. It creates some new blocks inside the .carousel parent (arrows to the left/right, dots for navigation, etc.). And it moves all the .item children inside the new .items block! I get such html structure after the plugin initialization:
<div class="carousel">
<div class="dots">...</div>
<div class="arrows">...</div>
<div class="items">
<div class="item"><img src="first.jpg" /></div>
<div class="item"><img src="second.jpg" /></div>
<div class="item"><img src="third.jpg" /></div>
</div>
</div>
When React tries to change the content of modalData.sliderHtml it executes some magic DOM operations for old structure removing. One of this operations is removeChild method, but the old .item elements can't be found inside the parent .carousel because the plugin moved them inside the new .items element. So, we get the error.
Bug fixing
I started to change modalData content back to the initialData structure every time when the modal is closed.
useEffect(() => {
$('#MyModal').on('hidden.bs.modal', function (e) {
setModalData(initialData);
})
}, []);
So, all html structure inside modalData.sliderHtml is filled by the initial empty data again and we don't get an error on the new link click.
SOLVED for bootstrap alert after manually close button
I had exact error when i close the bootstrap alert error message if it's there manually and then submit the form again. what i had done is to wrap up the AlertError component with extra tag around.
import React from "react";
const AlertError = (props) => {
return (
<div> // <---- Added this
<div className="alert alert-custom alert-notice alert-light-danger fade show" role="alert">
<div className="alert-icon"><i className="flaticon-warning"></i></div>
<div className="alert-text">There is an error in the form..!</div>
<div className="alert-close">
<button type="button" className="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true"><i className="ki ki-close"></i></span>
</button>
</div>
</div>
</div> // <---- Added this
);
};
export default AlertError;
I had same problems with a audio tag and I kept this tag within two nested div and now its working
Most probable cause: something modified the DOM after React
The most probable cause of this issue is that something other than React modified the DOM after React rendered to it.
What's causing this DOM mutation?
Depending on the profile of users who are impacted, there might be a few different causes.
Everyone
If all your users are impacted, you, the developer might be the culprit.
The cause is probably that you are using jQuery or doing DOM manipulations outside of React.
Usual users
If usual users are affected, the most probable cause is Google Chrome translate feature (or Microsoft translate on Edge Chromium).
Thankfully there's an easy solution for that: add a <meta> tag in your HTML <head> (Google documentation).
<meta name="google" content="notranslate" />
This should also disable Microsoft Translator on Edge Chromium.
Advanced users
If only advanced users are affected, and they are not using a translation feature on their browser, then it might be a browser extension or some userscript (most likely run by SpiderMonkey) that causes the problem.
More info
Issue on React repo
SolidJS is also affected
Issue on Chromium bug tracker (please star it to help prioritize it)
This is a very annoying bug to fix. But you should wrap the component that you are rendering it conditionally with span element.
Check this GitHub issue: https://github.com/facebook/react/issues/11538#issuecomment-390386520
In one place of our code was something like this:
render() {
if (el) return <div />
return '';
}
After replacing ' ' with null, all works without errors.
I had the same issue with react. The problem was caused by a google-auth script tag in index.html.
<script src="https://accounts.google.com/gsi/client" async defer></script>
This is while I had another on the JS file causing the issue. Be sure to check for conflicting or repeated CDNs.
In my case, I just needed to reset the state OR make it to initial data when I needed to render it with new data. It fixed the issue.
Ex:
This issue occurred when I was setting table data upon getting API response in useFetch. Before setting the data to state, I first set it to initial value.
setTableData([]);
setTableData(data.response);
I hope it may help someone.
Node.removeChild() - Web APIs | MDN
Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
fix:
unmountContainer() {
// macro task
setTimeout(() => {
// refs
if (containerEle) {
// receive removed node
// eslint-disable-next-line no-unused-vars
let removedChild = document
.querySelector('.page__wrapper')
.removeChild(containerEle);
}
});
}

Error: [$parse:syntax] when using ng-class

I have been following a pluralsight course called Creating Apps with Angular, Node and Token Authentication, and am writing my own custom alert messaging.
Basically, what I want to do, is to add different CSS classes depending on the state of the alert message.
When I load my app, I get the following error in the console:
Error: [$parse:syntax] Syntax Error: Token '}' is unexpected, expecting [:] at column 83 of the expression [{'flipInY': alert.show, 'flipOutY':!alert.show, 'alert-hidden:!alert.hasBeenShown'}] starting at [}]
I don't understand, since I'm pretty sure my syntax is correct. Can anybody point out what I'm doing wrong?
My html:
<div class="container" ng-cloak>
<div ui-view></div>
<div class="alert alert-{{alert.type}} animated main-alert" ng-class="{'flipInY': alert.show, 'flipOutY':!alert.show, 'alert-hidden:!alert.hasBeenShown'}"><strong>{{ alert.title }}</strong>
{{ alert.message }}
</div>
</div>
If you need more details, please ask, or check the Github repo. The relevant files are index.html in the root folder, register.js under app/scripts/controllers and alert.js under app/scripts/services.
Thanks for the help.
Change this:
'alert-hidden:!alert.hasBeenShown'
to this:
'alert-hidden':!alert.hasBeenShown
You missed a closing single-quote in property name.

Categories

Resources