How to create button which adds new Vue-Grid-Item? - javascript

I am creating a program for my Universities Research department, the program is for the operation of an Atomic Layer Deposition system.
The program needs to be able to allow the user to set a custom 'recipe' if you will, each grid-item will have a button with 'edit' in the bottom corner, and will take you to a separate page where you can enter your system stats like zone temps, durations, cycles, etc. We have gotten the draggable grid-items working, so that we could make the system run multiple steps over and over if we wish, but here is my goal I can't seem to accomplish:
We need to be able to add a new 'step' grid-item on button click, and we need to be able to remove a grid-item as well. I have created a button 'New Tile' and I defined a function I was hoping would work, I was trying to see if I could duplicate a grid item, but when I run the program and click the button I get the error:
"[Vue warn]: Property or method "duplicate" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties."
Image of app: https://imgur.com/a/DgKebPR
image of JS trying to be used: https://imgur.com/a/EjW4t6d
<h2 style="color: #f6a821;">Steps</h2>
<hr class="hr" />
<grid-layout
:layout.sync="stepsGrid"
:col-num="8"
:row-height="75"
:is-draggable="true"
:is-resizable="false"
:is-mirrored="false"
:vertical-compact="true"
:margin="[50, 50]"
:use-css-transforms="true">
<div id="duplicater">
<grid-item
:x=stepsGrid[0].x
:y=stepsGrid[0].y
:w=stepsGrid[0].w
:h=stepsGrid[0].h
:i=stepsGrid[0].i
:isDraggable=stepsGrid[0].isDraggable>
<div class="Panel__name">1</div>
<div class="editButton">
<router-link to="/Parameters-template" class="editButton">Edit</router-link></router-link>
</div><br>
<div class="Panel__status">Status:</div>
</grid-item>
<div id="bottombuttons">
<button id="resetbutton">Reset</button>
<button id="startbutton" #click="duplicate()">New Tile</button>
</div>
</div>

I don't get where is declared the duplicate method extactly. Don't expect it to be available from a template if it's not declared in the component's methods. Try:
methods: {
duplicate() {
/* */
}
}
in the same component. If it needs to be a shared among several components, put this in a mixin.

Related

Vue - transition-group not working with different type of components

I have a project where I use Vue Transitions in order to animate the sorting and filtering a grid containing car components. Each grid elements contains one car-component.
The problem is that the user can invite new users to the platform. Those new users/cars are not the same objects as the existing objects that each is shown in a car-component. In these new objects I show different type of data/information.
This is why I have chosen to show these 'new' users using a different type of component then the car-components.
The problem is that both components need to be shown inside the same CSS grid. But when I try to add both components inside a transition group, that transition group breaks and it no longer performs the sorting animations.
<transition-group class="grid">
<InvitedUsers v-for="invite in Invited" />
<Users v-for"user in Users" />
</transition-group>
Is there a way around this? Can I add bot set of items inside the same CSS grid and still have the transition group do its work? I have tried the following, but it doesn't work because both set of items are created in different grids. But this way the transition-group works again.
<div class="grid">
<InvitedUsers v-for="invite in Invited" />
</div>
<transition-group class="grid">
<Users v-for"user in Users" />
</transition-group>
I have struggled with the same issue once. We can not directly wrap components inside <transition-group>, there has to be another wrapper around the component.
Here is an example
<transition-group class="grid">
<div v-for"user in Users">
<Users />
</div>
<div v-for="invite in Invited">
<InvitedUsers />
</div>
</transition-group>
You may have to adjust your grid container a little bit.

Setting raised = true to an ember button when on current page/template

<div class="flex">
<div class="layout-row layout-align-end-center">
{{#paper-button href="overview" raised=true primary=true}}Overview{{/paper-button}}
{{#paper-button href="incomes"}}Incomes{{/paper-button}}
{{#paper-button href="expenses"}}Expenses{{/paper-button}}
{{#paper-button href="settings"}}Settings{{/paper-button}}
</div>
</div>
So I am trying to set the raised=true whenever I am on certain page/template. The above code is from my application template. Is there any way of doing this using JS/Ember or should I just do it manually in each of my templates?
I think the best way to go is to write a custom component wrapping paper-button. ember-route-helpers gives you nice helpers to do that:
{{#paper-button
onclick={{transition-to #route)
href=(url-for #route)
raised=(is-active #route)
primary=(is-active #route)
}}
{{yield}}
{{/paper-button}}
Then you can use that component with {{#your-component route="settings"}}Settings{{/your-component}}.
It's important to understand that you should pass both the action and the href. Because then when people click on the button it will make a transition and dont reload the entire page, but rightlick->open and screenreaders are are not broken.

How can I configure facebook plugin for vuejs with slots

I need to integrate facebook plugin into my vuejs application. I wanted to use
vue-facebook-login-component plugin but I am confused at some points. I can not change text, it doesnt have a text prop, instead it has a text slot. And their slot example doesnt have a api-id which needed for facebook login.
They have to slot example but I could not understand how to use it, never used slot before. I searched google but still can not make it.
When I used in my code, slot-scope="scope" gives scope is defined but never used error, so my first question is how will I use it ?
Another issues is, in slot example it doesnt have app-id, I confused where to put id when I use slot, and how to get login-logout information.
this one works but I can not change login/logoutworking texts.
<v-facebook-login app-id="966242223397117"></v-facebook-login>
this is the example with slot given on the plugin page
<template>
<v-facebook-login-scope>
<button slot-scope="scope">
<!-- Compose HTML/CSS here, otherwise nothing will be rendered! -->
</button>
</v-facebook-login-scope>
</template>
and this is my original button code where I want to integare facebook login. How will I use his code in above code-with-slot ? and where will I put app-id ? Here it is a more detailed code with slot from the plugin and it doesnt have api-id either.
https://github.com/adi518/vue-facebook-login-component/blob/master/src/components/FBLogin.vue
<v-button
class="gray fw shadow-none login-box__submit"
title="FACEBOOK İLE GİRİŞ YAP"
/>
so what I tried is directly putting my button inside of it (just giving class doesnt work)
This brings button with my button class but stays connecting and never bring login
<template>
<v-facebook-login-scope>
<button slot-scope="scope">
<!-- Compose HTML/CSS here, otherwise nothing will be rendered! -->
<v-button
class="gray fw shadow-none login-box__submit"
title="FACEBOOK İLE GİRİŞ YAP"
/>
</button>
</v-facebook-login-scope>
</template>
Try this
<v-facebook-login app-id="966242223397117">
<span slot="login">FACEBOOK İLE GİRİŞ YAP</span>
</v-facebook-login>

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);
}
});
}

Include component from parent app in component contained in node_modules directory

I am working on Vue app that incorporates Vue Bootstrap Calendar, and I would like to be able to override the content of the day cell (handled by the Day.vue component) to add my own custom content inside. My thought was initially to modify the Day component to include <slot></slot> tags and pass in the custom content that way.
The problem has to do with accessing the Day component. To include the calendar in your app, you include the Calendar.vue component, which includes Week.vue, which in turn includes Day.vue. As I understand slots, I have to have the child component (Day.vue in this case) included in the component where I'm passing the data, which means it would need to be included in my own component.
If this is not possible, my other thought is to perhaps modify the library by adding another configuration prop (something like dayCustomContent) to the Calendar.vue that indicates that the Day cell content is custom content, pass that in to Calendar.vue, and then down to Day.vue, and then in the Day.vue template, have a v-if conditional based on this prop that either displays the custom content or the default cell content, something like:
<template>
<div class="day-cell" v-if="dayCustomContent">
...my custom content here...
</div>
<div class="day-cell" v-else>
...default events from my.events goes here...
</div>
</template>
I would probably then need to define a custom component to render whatever custom content I want to display, and somehow include that component within Day.vue.
So to sum up, my questions are these:
1) Is there a way to do what I need with slots?
2) For my second option, am I going down the right path? I'm open to suggestions.
UPDATE: I was able to get this done by adding a boolean customDayContent prop in Calendar.vue like so and passing it down to Week.vue and then to Day.vue:
<template>
...
<div class="dates" ref="dates">
<Week
v-for="(week, index) in Weeks"
:firstDay="firstDay"
:key="week + index"
:week="week"
:canAddEvent="canAddEvent"
:canDeleteEvent="canDeleteEvent"
:customDayContent="customDayContent"
:displayWeekNumber="displayWeekNumber"
#eventAdded="eventAdded"
#eventDeleted="eventDeleted"
></Week>
</div>
...
</template>
<script>
export default {
...
props: {
...
customDayContent: {
type: Boolean,
default: false
}
},
}
</script>
and then in Day.vue, do like I had suggested with v-if:
<template>
<div class="day-cell" v-if="customDayContent">
<custom-day></custom-day>
</div>
<div
class="day-cell"
:class="{'today' : day.isToday, 'current-month' : day.isCurrentMonth, 'weekend': day.isWeekEnd, 'selected-day':isDaySelected}"
#click="showDayOptions"
v-else
>
... existing code goes here...
</div>
</template>
The last part is referencing the CustomDay.vue component referenced in my v-if block. I want the user to be able to define the content of their own custom CustomDay.vue template in their own parent app. However, I'm having trouble trying to figure out how to do that. Following the pattern of including components already in this component, I added this in the components section of Day.vue:
CustomDay: require("../../../../src/Components/CustomDay.vue").default
? require("../../../../src/Components/CustomDay.vue").default
: require("../../../../src/Components/CustomDay.vue")
However, no matter what I try along these lines, I get an error that the relative module was not found. On top of that, I need to add it to the componentsarray only if customDayContent is true. What is the best way to do that? In a watcher or computer property, perhaps? Or another way?

Categories

Resources