append div with additional functon - javascript

I have an odd task. I am simply trying to add an additonal function on an element when its clicked. I cant seem to trigger the addScroll function that is found within my methods. As you can see, the div should be appended to the screen when the button is clicked. Once that div is clicked as well, the remove method is applied and I also want to apply the addScrollBack().
new Vue({
el: "#app",
data: {
chocs: [
{ text: "Learn JavaScript", done: false },
{ text: "Learn Vue", done: false },
{ text: "Play around in JSFiddle", done: true },
{ text: "Build something awesome", done: true }
]
},
methods: {
addScrollBack: function(){
alert("test");
},
handlePosterClick: function(choc){
alert("ckciked")
window.top.$(".2l-body").css("overflow","hidden");
$("#cook").append(`<div style="background-color:blue;height:200px; width:300px" onclick="document.querySelector('#popover-div').remove();addScrollBack();>test</div>`);
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="cook">
</div>
<button v-on:click="handlePosterClick(choc)">
Book
</button>
</div>

Look at this :
https://codepen.io/hl037/pen/QWOjwyK
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
{{displayDiv}}
<div id="cook">
<div
v-if="displayDiv"
style="background-color:blue;height:200px; width:300px"
v-on:click="onDivClicked"
>
test
</div>
</div>
<button v-on:click="displayDiv=true">
Book
</button>
</div>
new Vue({
el: "#app",
data: {
displayDiv:false,
chocs: [
{ text: "Learn JavaScript", done: false },
{ text: "Learn Vue", done: false },
{ text: "Play around in JSFiddle", done: true },
{ text: "Build something awesome", done: true },
],
},
methods: {
onDivClicked(){
/*document.querySelector('#popoverdiv').remove();*/
this.addScrollBack();
},
addScrollBack: function(){
alert("test");
},
handlePosterClick: function(choc){
},
}
})
...Instead of manipulating the dom yourself, just use vue's template, with a model controlling its behavior. The same applies to your other component (the popup) : it should instead listen on a custom event on this component to add/remove scroll using reactivity.
Using vanilla javascript for dom modification, event-handling etc. is NOT recommended with vue. Always use vue's way of doing it. vanilla dom modification should only be done by experts, mostly to interface with non-vue code.

Not clear, but suggestion is use v-html instead of append
new Vue({
el: "#app",
data: {
cook: "Old content OR blank",
chocs: [
{ text: "Learn JavaScript", done: false },
{ text: "Learn Vue", done: false },
{ text: "Play around in JSFiddle", done: true },
{ text: "Build something awesome", done: true }
]
},
methods: {
addScrollBack: function(){
alert("test");
},
handlePosterClick: function(choc){
//alert("ckciked " + choc)
// window.top.$(".2l-body").css("overflow","hidden");
// inline Scripting not recommanded,
this.cook= `<div style="background-color:blue;height:200px; width:300px" >test</div>`;
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="cook" v-html="cook">
</div>
<button v-on:click="handlePosterClick('choc')">
Book
</button>
</div>

Related

Vuejs strange behavior when a list of checkboxes are updated

Well, it's not easy to explain.
I have a list of checkboxes generated from reactive data. When you check one of the checkboxes, one of the entries of the reactive data is deleted.
The list is then updated.
The next checkbox is then placed under the mouse cursor and is "activated" by releasing the mouse button. This behavior is unwanted, can you see a way to avoid this?
Here is the code to illustrate this case:
<div id="app">
<h2>Todos:</h2>
<ol>
<li v-for="todo in todos">
<label>
<input type="checkbox"
v-on:change="toggle">
{{ todo.text }}
</label>
</li>
</ol>
</div>
Script part:
new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript" },
{ text: "Learn Vue" },
{ text: "Play around in JSFiddle" },
{ text: "Build something awesome" }
]
},
methods: {
toggle: function(){
this.todos.splice(1,1)
}
}
})
Also a live test: https://jsfiddle.net/m10jyLut/7/
I don't know if my design is correct. I would like to avoid a too hackneyed solution.
Thank you very much for your guess.
I added "key" to v-for, which is always a good idea, and passing todo.id with toggle().
<div id="app">
<h2>Todos:</h2>
<ol>
<li v-for="todo in todos" :key="todo.id">
<label>
<input type="checkbox"
v-on:change="toggle(todo.id)">
{{ todo.text }}
</label>
</li>
</ol>
</div>
Your script tag should be like this:
new Vue({
el: "#app",
data: {
todos: [
{ id: Math.random() * 100000, text: "Learn JavaScript", },
{ id: Math.random() * 100000, text: "Learn Vue", },
{ id: Math.random() * 100000, text: "Play around in JSFiddle", },
{ id: Math.random() * 100000, text: "Build something awesome", }
]
},
methods: {
toggle(id) {
this.todos = this.todos.filter(todo => todo.id !== id)
}
}
})
In Vue.js, it's always a good idea to add key to v-for, and working with ids for rendering operations.

Clearing Text Fields on button click in Vue.js?

I have a layout on which i am looping to get text fields and a button. How do i add a function on the button so that it clears only it's respective fields.
Check out the fiddle here.
<div id="app">
<h2>Each text with it's own state and clear should clear the respective
text fields</h2>
<ul v-for="todo in todos">
<li>
<input type="text" :placeholder="`${todo.text}`">
</li>
<li>
<input type="text" :placeholder="`${todo.text1}`">
</li>
<button>Clear</button>
</ul>
new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript", text1:"Hey" },
{ text: "Learn Vue", text1:"Hello" },
{ text: "Play around in JSFiddle", text1:"Ciao" },
{ text: "Build something awesome", text1:"Something"}
]
}
})
If you want to clear a specific fields you could add a method clear which takes the index as parameter but before that you should add value and value1 items to each todo and bind them to fields as follows:
new Vue({
el: "#app",
data: {
todos: [{
text: "Learn JavaScript",
text1: "Hey",
value1:'',
value:''
},
{
text: "Learn Vue",
text1: "Hello",
value1:'',
value:''
},
{
text: "Play around in JSFiddle",
text1: "Ciao",
value1:'',
value:''
},
{
text: "Build something awesome",
text1: "Something",
value1:'',
value:''
}
]
},
methods:{
clear(i){
this.todos[i].value='';
this.todos[i].value1='';
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<h2>Each text with it's own state and clear should clear the respective text fields</h2>
<ul v-for="(todo,i) in todos">
<li>
<input type="text" :placeholder="`${todo.text}`" v-model="todo.value">
</li>
<li>
<input type="text" :placeholder="`${todo.text1}`" v-model="todo.value1">
</li>
<button #click="clear(i)">Clear</button>
</ul>
</div>
You really should go through the docs at https://v2.vuejs.org/v2/
You are missing many of the basic constructors to achieve your objective. First, you will need to add the click event to your button. (https://v2.vuejs.org/v2/guide/events.html)
Next, you will need to reference the index of the todos during rendering (https://v2.vuejs.org/v2/guide/list.html)
From here you can create a simple method called clear:
new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript", text1:"Hey" },
{ text: "Learn Vue", text1:"Hello" },
{ text: "Play around in JSFiddle", text1:"Ciao" },
{ text: "Build something awesome", text1:"Something"}
]
},
methods: {
clear (index) {
// Allows for unlimited keys
for (let key in this.todos[index]) {
this.$set(this.todos[index], key, null);
}
}
}
})
Notice that in the clear method I am ensuring reactivity by using the $set method (https://v2.vuejs.org/v2/api/#vm-set) and referencing the index that was passed.
Lastly, I bound the inputs value to the todo model using Vue's v-model, do I get extra credit? (https://v2.vuejs.org/v2/api/#v-model)
Completed code:
https://jsfiddle.net/cdsgu62L/10/

Use a template in vue component passed as a prop

I'm a total newbie, so please bear with me if I'm still grasping with the coding fundamentals.
I want to use a template that is defined in the prop. The template is inside the DOM. The reason I want to do it this way is that I want to reuse the component logic (specifically the pagination), but may want to change how the way the template displays the data in different pages. So I wanted to seaparate the template from the script file.
This is the HTML File:
<div id="store-list">
<paginated-list :list-data="stores" use-template="#displayList"></paginated-list>
</div>
<script type="text/template" id="display-list">
<div>
<div v-for="p in paginatedData">
{{p.BusinessName}}
</div>
</div>
</script>
This is the .js file:
Vue.component('paginated-list', {
data() {
return {
pageNumber: 0
}
},
props: {
listData: {
type: Array,
required: true
},
useTemplate: {
type: String,
required: false
},
size: {
type: Number,
required: false,
default: 10
}
},
computed: {
pageCount() {
let l = this.listData.length,
s = this.size;
return Math.floor(l / s);
},
paginatedData() {
const start = this.pageNumber * this.size,
end = start + this.size;
return this.listData
.slice(start, end);
}
},
//template: document.querySelector('#display-list').innerHTML // this works
template: document.querySelector(useTemplate).innerHTML // this does not
});
var sl = new Vue({
el: '#store-list',
data: {
stores: [{
"BusinessName": "Shop Number 1"
}, {
"BusinessName": "Shop Number 2"
}, {
"BusinessName": "Shop Number 3"
}]
}
});
var shoppingList = new Vue({
el: '#shopping-list',
data: {
header: 'shopping list app',
newItem: '',
items: [
'1',
'2',
'3',
]
}
})
Any help is greatly appreciated. Thank you.
You can use the inline-template attribute to override the component's template at render time. For example
<paginated-list :list-data="stores" inline-template>
<div>
<div v-for="p in paginatedData">
{{p.BusinessName}}
</div>
</div>
</paginated-list>
See https://v2.vuejs.org/v2/guide/components-edge-cases.html#Inline-Templates
Your component can still have a default template but this will override it if set.

How to iterate over a div enyos component?

enyo.kind({
name: "Usr",
kind: enyo.Control,
published: {
username: "",
ToDo: [],
Done:[]
},
components: [
{tag:"title",name:"username"},
{tag:"input", name:"desc", placeholder: "to do..",
style:"width:500px; static: left; padding-right: 10px"},
{tag: "button", content: "New Task", ontap: "addTask",
style:"float: right; padding-left: 10px;
background-color:orange; color:white" },
{tag: "div", name: "ToDo" }
],
addTask: function(inSource, inEvent) {
this.createComponent({
kind: Task,
container: this.$.ToDo,
text: this.$.desc.hasNode().value,
state: "To do"
});
this.$.ToDo.render();
}
})
So, this is what i have. As you can see, I create new elements (Task kind is defined in other js file, doesn´t really matters) using (addTask) and putting them inside the ToDo "div" component. How can I iterate over those elements? something like a 'for each' sentence or so, maybe is there a $'div'.length property or something? I haven´t found an answer in any official documentation.

Vue.JS Vue-Tables Laravel Relationship

I am using https://github.com/matfish2/vue-tables with Laravel.
This is the vue code:
Vue.use(VueTables.client, {
compileTemplates: true,
highlightMatches: true,
pagination: {
dropdown:true,
chunk:5
},
filterByColumn: true,
texts: {
filter: "Search:"
},
datepickerOptions: {
showDropdowns: true
}
});
new Vue({
el: "#people",
methods: {
deleteMe: function(id) {
alert("Delete " + id);
}
},
data: {
options: {
columns: ['created_at', 'name', 'profession', 'footage_date', 'type', 'link', 'note'],
dateColumns: ['footage_date'],
headings: {
created_at: 'Added',
name: 'Name',
profession: 'Profesion',
footage_date: 'Footage Date',
type: 'Type',
link: 'Link',
note: 'Note',
edit: 'Edit',
delete: 'Delete'
},
templates: {
edit: "<a href='#!/{id}/edit'><i class='glyphicon glyphicon-edit'></i></a>",
delete: "<a href='javascript:void(0);' #click='$parent.deleteMe({id})'><i class='glyphicon glyphicon-erase'></i></a>"
},
},
tableData: [{ InsertDataHere }],
}
});
How do I get the data from DB for tableData ? Vue-resources?
I have a route /api/footage that gives me the following
[
{
"id": 2,
"user_id": 11,
"profession": "profession",
"type": "GvG",
"footage_date": {
"date": "2016-04-01 00:00:00.000000",
"timezone_type": 2,
"timezone": "GMT"
},
"link": "some link",
"note": "description",
"created_at": "1 hour ago",
"updated_at": "2016-04-03 23:06:32"
}
]
Now, User and Footage have a one to many relationship. How would I go about to show the user for each entry as well? ( also the ID for edit and delete )
This is the blade code
<div id="people" class="container">
<v-client-table :data="tableData" :options="options"></v-client-table>
</div>
Thank you in advance.
You can add a ready() function to call the API when the component is built:
ready:function(){
this.$http.get('/api/footage')
.then(function(response){
this.tableData = response.data
}.bind(this))
}
You may have to tweak the code based on the format of your API response. Cleaner version if youre using es2016:
ready(){
this.$http.get('/api/footage')
.then(({data})=>{
this.tableData = data
})
}
You should include vue-resource before this, yes. That allows you to use this.$http
As per #BillCriswell you could do this in the created() function to fire off the API call even sooner
When fetching async data use v-if along with some "loaded" flag on the component to ensure smooth compilation of templates.
<v-client-table v-if="loaded" :data="tableData" :options="options"></v-client-table>
See: https://github.com/matfish2/vue-tables/issues/20, last comment

Categories