Vue js attributes in xpage Vue.js - vue.js

Attributes not rendered when running xpage:
:Source code:
<div id="categories" class="article-search-results-categories">
<ul class="table-view">
<li class="table-view-cell pr40" v-for="row in list.categories">
<xp:span id="clickSpan">{{row.name }}
<xp:this.attrs>
<xp:attr name="v-on:click" value="alert('ok')" rendered="true"
</xp:attr>
</xp:this.attrs>
</xp:span>
</li>
</ul>
</div>
Script
var app = new Vue ({
el: '#app',
data: {
list:[]
},
methods:{
getUsers: function(){
var link = 'https://jsonplaceholder.typicode.com/users';
this.$http.get(link).then(function(response){
this.list = response.data;
}, function(error){
console.log(error.statusText);
});
},
getCategoryJSON: function(){
var config = {
headers : {
'Content-Type' : 'application/json'
}
}
var data = {
"supplierid": "DAHL"
};
data = JSON.stringify(data);
axios.post
('ProductViewJSONCtrl.xsp',data,config).then(function(response){
app.list = response.data;
}, function(error){
console.log(error.statusText);
});
},
getLevel: function(row){
console.log('clicked');
}
},
mounted : function(){
console.log("in mounted");
this.getCategoryJSON();
}
});
Output:
<span id="view:_id1:_id2:_id295:includeBody:_id328:clickSpan">VA-
armatur/Stängventiler</span>
Any ideas why these attributes can't render?
The example with just the xpage tag is correctly generated but the problem is when the spabn is in the v-for loop
Edited m surrounding codeas the problem is when VUE.js attahces and runs for loop

This
<xp:span
id="clickSpan">
{{row.name }}
<xp:this.attrs>
<xp:attr
name="v-on:click"
value="alert('ok')"
rendered="true" />
</xp:this.attrs>
</xp:span>
renders
<span id="view:_id1:clickSpan" v-on:click="alert('ok')">{{row.name }}</span>
So, it works.
I guess you have a syntax error in source panel and your changes don't take effect yet.

Related

Cant store api data called by axios in array through mounted, unless clicking on <Root> element from vue devtools (in browser)

i'm using axios to get data from api and store in an array after mounting then run a search query in the array later on, but it's not working unless i click on Root element in browsers Vue developer tools, after i click on vue Root element from vue dev tool everything works fine.Here is my code..
<script type="module">
const vueApp = new Vue({
el: "#pos",
data: {
searchTerm: "",
allProducts: [],
selectedProducts: [],
suggestions: []
},
mounted: function (){
axios.get("api/products").then( res => this.allProducts = res.data );
},
methods: {
select(item){
this.selectedProducts.push(item);
this.suggestions = [];
}
},
computed:{
matches(){
if(!this.searchTerm) return;
this.suggestions = this.allProducts.filter(sP=>(sP.prod_name).includes(this.searchTerm));
}
}
});
</script>
//HTML below------------------
<div id="pos">
<input type="text" v-model="searchTerm">
<ul v-for="match in suggestions">
<li #click="select(match)">
{{match.prod_name}}
</li>
</ul>
<table>
<tr v-for="(product,i) in selectedProducts">
<td>#{{product.prod_name}}</td>
</tr>
</table>
</div>
const vueApp = new Vue({
el: "#pos",
data: {
searchTerm: "",
allProducts: [],
selectedProducts: [],
suggestions: []
},
mounted: function() {
axios.get("api/products").then(res => this.allProducts = res.data);
},
methods: {
select(item) {
this.selectedProducts.push(item);
this.suggestions = [];
}
},
computed: {
matches() {
if (!this.searchTerm) return;
this.suggestions = this.allProducts.filter(sP => (sP.prod_name).includes(this.searchTerm));
}
}
});
<div id="pos">
<input type="text" v-model="searchTerm">
<ul v-for="match in suggestions">
<li #click="select(match)">
{{match.prod_name}}
</li>
</ul>
</div>
As I mentioned in the comments on your question, this is an error I cannot seem to understand how you are getting. I sense there is information that we are not being presented with.
As such, here is a quick "working" example of fetching items from the mounted lifecycle hook in a component. Note: If you are creating the component via a Single-File Component (.vue files) then don't worry too much about the declaration, pay attention only to the data and mounted methods.
const App = Vue.component('App', {
template: `<div>
<input v-model="searchTerm" type="search">
{{items.length}} results fetched
</div>`,
data() {
return {
searchTerm: '',
items: []
}
},
mounted() {
//Timeout used to mimic axios query
setTimeout(()=> this.items= [1,2,3,4], 1000)
}
});
const app = new App({
el: '#app'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">Placeholder</div>
Edit
The code you have given us after your update seems to be working just fine. See the below snippet.
I noticed you are looping over suggestions but that value is never updated anywhere in your given code.
const vueApp = new Vue({
el: "#pos",
data: {
searchTerm: "",
allProducts: [],
selectedProducts: [],
suggestions: []
},
mounted: function() {
setTimeout(() => this.allProducts = [1,2,3,4,5], 1000);
},
methods: {
select(item) {
this.selectedProducts.push(item);
this.suggestions = [];
}
},
computed: {
matches() {
if (!this.searchTerm) return;
this.suggestions = this.allProducts.filter(sP => (sP.prod_name).includes(this.searchTerm));
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="pos">
<input type="text" v-model="searchTerm">
<ul v-for="match in suggestions">
<li #click="select(match)">
{{match.prod_name}}
</li>
</ul>
{{allProducts.length}} results loaded
</div>
mounted: function(){
var _self = this;
axios.get("api/products").then( res => _self.allProducts = res.data );
}

Vue.js i cant display fetched data

Im fetching a feed with fetch, but somehow my vue app does not render it i have tried diffrent things but nothing seems to work for me.
<section id="vue-instagram" class="instagram">
<div class="instagram__col" v-for="item in feed">
<div class="instagram__col__picturebox">
<img v-if="item.media_url.indexOf('.mp4') == -1" v-bind:src="item.media_url"/>
<video v-if="item.media_url.indexOf('.mp4') > 0" loop preload muted controls style="width:100%;">
<source v-bind:src="item.media_url" />
</video>
</div>
<div class="instagram__col__description">
<div class="instagram__col__descroption--icon">
<img src="images/insta.png"/>
</div>
<div class="instagram__col__descroption--text">
{{item.caption.substring(0,90)}}...
<div class="hashtags bold-text">
{{item.caption.substring(item.caption.indexOf('#'), item.caption.length).split(' ').slice(0,5).join(' ')}}
</div>
</div>
</div>
</div>
</section>
var app = new Vue({
el: '#vue-instagram',
data:() => ({
loading: false,
feed: [],
}),
}, created: async () => {
var response = await fetch("URL_TOSERVER", {
method: "POST",
});
var {data} = await response.json();
this.feed = data;
console.log(data);
});
If I call this.feed in chrome it displays the data but if I drill into app.data its empty.
The solution was to extract the call as a method
new Vue({
el: '#vue-instagram',
data: {
loading: false,
feed: [],
},
created: function() {
this.fetchData();
},
methods: {
fetchData: function(){
var self = this;
fetch("http://727.dk.web81.curanetserver.dk/umbraco/api/instagram/index", {
method:"POST"
}).then(function(response){
return response.json();
}).then(function(data){
self.feed = data.data;
});
}
},
computed: {
posts: function() {
return this.feed;
}
}
});

VueJS 2 update contenteditable in component from parent method

I have editable element updated by component method, but i have also json import and i want to update element my parent method. I can update model, but editable element doesn´t bind it. If i insert content to component template, it will bind updated model, but then i can´t really edit it.
Here´s my example: https://jsfiddle.net/kuwf9auc/1/
Vue.component('editable', {
template: '<div contenteditable="true" #input="update"></div>', /* if i insert {{content}} into this div, it wil update, but editing behave weird */
props: ['content'],
mounted: function () {
this.$el.innerText = this.content;
},
methods: {
update: function (event) {
console.log(this.content);
console.log(event.target.innerText);
this.$emit('update', event.target.innerText);
}
}
})
var app = new Vue({
el: '#myapp',
data: {
herobanner: {
headline: 'I can be edited by typing, but not updated with JSON upload.'
}
},
methods: {
uploadJSON: function (event) {
var input = event.target;
input.src = URL.createObjectURL(event.target.files[0]);
var data = input.src;
$.get(data, function(data) {
importdata = $.parseJSON(data);
this.$data.herobanner = importdata.herobanner;
}.bind(this));
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<main id="myapp" class="container-fluid">
<input type="file" id="file" name="file" #change="uploadJSON" style="display: none; width: 1px; height: 1px"/>
<a href="" onclick="document.getElementById('file').click(); return false" title="Import settings from JSON file">
upload JSON
</a>
<h1>
<editable :content="herobanner.headline" #update="herobanner.headline = $event"></editable>
</h1>
Real value of model:
<br>
<h2>{{herobanner.headline}}</h2>
</main>
Working example:
Vue.component('editable', {
template: `
<div contenteditable="true" #blur="emitChange">
{{ content }}
</div>
`,
props: ['content'],
methods: {
emitChange (ev) {
this.$emit('update', ev.target.textContent)
}
}
})
new Vue({
el: '#app',
data: {
herobanner: {
headline: 'Parent is updated on blur event, so click outside this text to update it.'
}
},
methods: {
async loadJson () {
var response = await fetch('https://swapi.co/api/people/1')
var hero = await response.json()
this.herobanner.headline = hero.name
},
updateHeadline (content) {
this.herobanner.headline = content
}
}
})
<main id="app">
<button #click="loadJson">Load JSON data</button>
<h1>
<editable
:content="herobanner.headline"
v-on:update="updateHeadline"
>
</editable>
</h1>
<h2>{{herobanner.headline}}</h2>
</main>
<script src="https://unpkg.com/vue#2.5.3/dist/vue.min.js"></script>

I am new to vue js ... can't display loaded data from a php file

Template part :
`<div class="col-sm-6" >
<ul class="list-group" id="pos">
<li class="list-group-item" v-for="(itm, index) in items">
<strong>{{index}} : {{ itm.sub }}</strong> - {{ itm.price }}
</li>
</ul>
</div>`
Script part :
new Vue({
el: '#pos',
http: {
root: '/vuetest',
headers: {
Authorization: 'Basic YXBpOnBhc3N3b3Jk'
}
},
data: {
items: []
},
created:function () {
this.$http.get('index.php').then(function(resp,status,request){
this.items = resp.data;
console.log(this.items); // got data but not displayed in browser
}.bind(this));
}
});
My Source files are from cdnjs.cloudeflare.com:
vue.js (2.1.4)
vue-resource.js (1.0.3).
Well, this isn't that...
created:function () {
this.$http.get('index.php').then(function(resp,status,request){
this.items = resp.data; // this is referring to the current function, and not to vue's scope.
console.log(this.items); // got data but not displayed in browser
}.bind(this));
}
So the correct use is:
created:function () {
var self = this
this.$http.get('index.php').then(function (resp,status,request) {
self.items = resp.data;
console.log(this.items);
});
}
As MU commented above, better you to use Arrows functions, so the "this" will have the scope you want.
mounted () {
}
Then you can access all your Data properties normally with "this".

Vuejs reactive v-if template component

I'm struggling to understand how to make my component reactive. At the moment the button is rendered correctly but once the create/delete event happens, the template does not change. Any tips on how to update the component after the event has taken place?
new Vue({
el: '#app'
});
Vue.component('favourite-button', {
props: ['id', 'favourites'],
template: '<input class="hidden" type="input" name="_method" value="{{ id }}" v-model="form.listings_id"></input><button v-if="isFavourite == true" class="favourited" #click="delete(favourite)" :disabled="form.busy"><i class="fa fa-heart" aria-hidden="true"></i><button class="not-favourited" v-else #click="create(favourite)" :disabled="form.busy"><i class="fa fa-heart" aria-hidden="true"></i></button><pre>{{ isFavourite == true }}</pre>',
data: function() {
return {
form: new SparkForm({
listings_id: ''
}),
};
},
created() {
this.getFavourites();
},
computed: {
isFavourite: function() {
for (var i = 0; this.favourites.length; i++)
{
if (this.favourites[i].listings_id == this.id) {
return true;
}
}
},
},
methods: {
getFavourites() {
this.$http.get('/api/favourites')
.then(response => {
this.favourites = response.data;
});
},
create() {
Spark.post('/api/favourite', this.form)
.then(favourite => {
this.favourite.push(favourite);
this.form.id = '';
});
},
delete(favourite) {
this.$http.delete('/api/favourite/' + this.id);
this.form.id = '';
}
}
});
Vue.component('listings', {
template: '#listing-template',
data: function() {
return {
listings: [], favourites: [],
};
},
created() {
this.getListings();
},
methods: {
getListings() {
this.$http.get('/api/listings')
.then(response => {
this.listings = response.data;
});
}
}
});
Vue expects HTML template markups to be perfect. Otherwise you will run into multiple issues.
I just inspected your template and found an issue - the first <button> element does not close.
Here is the updated version of your code:
Vue.component('favourite-button', {
props: ['id', 'favourites'],
template: `
<input class="hidden" type="input" name="_method" value="{{ id }}" v-model="form.listings_id"></input>
<button v-if="isFavourite == true" class="favourited" #click="delete(favourite)" :disabled="form.busy">
<i class="fa fa-heart" aria-hidden="true"></i>
</button> <!-- This is missing in your version -->
<button class="not-favourited" v-else #click="create(favourite)" :disabled="form.busy">
<i class="fa fa-heart" aria-hidden="true"></i>
</button>
<pre>{{ isFavourite == true }}</pre>
`,
...
Note the comment on 7th line above, the closing </button> tag is not present in your template.
As a side note, if you do not want to type back-slash at the end of every line to make multi-line template strings, you can use back-ticks as shown in my code example above. This will help you avoid markup errors leading to Vue component issues and many hours of debugging.
Another reference: Check out "Multi-line Strings" in this page: https://developers.google.com/web/updates/2015/01/ES6-Template-Strings
Relevant lines (copied from above page):
Any whitespace inside of the backtick syntax will also be considered part of the string.
console.log(`string text line 1
string text line 2`);
EDIT: Found a possible bug in code
Here is another issue in your create method of favourite-button component:
methods: {
// ...
create() {
Spark.post('/api/favourite', this.form)
.then(favourite => {
this.favourite.push(favourite); // Note: This is the problem area
this.form.id = '';
});
},
//...
}
Your success handler refers to this.favourite.push(...). You do not have this.favourite in data or props of your component. Shouldn't it be this.favourites?