EDIT: Answered, increment and decrement changed the values. '#' + (post.id+1) and '#' + (post.id-1) do not, thansk blex.
I have a series of id'ed divs that I want to navigate to the next one and the previous one through links.
Using vue.js, I want to put in a JavaScript expression in the href to add one to the current id to function as a "next" button, and have another link that subtracts one from the current id to function as a "previous" button.
Here is my HTML, where I have a Vue Component:
<script src="https://unpkg.com/vue"></script>
<div id="blog-post-demo" class="demo">
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
</div>
And here is my JavaScript, where I make the component and template:
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post" v-bind:id="post.id">
<h1>{{ post.title }}</h1>
<div v-html="post.body"></div>
<a :href="'#' + post.id--">Previous Entry</a>
<a :href="'#' + post.id++">Next Entry</a>
</div>
`
})
new Vue({
el: '#blog-post-demo',
data: {
posts: []
},
created: function () {
// Alias the component instance as `vm`, so that we
// can access it inside the promise function
var vm = this
// Fetch our array of posts from an API
fetch('https://api.myjson.com/bins/1bjyk2')
.then(function (response) {
return response.json()
})
.then(function (data) {
vm.posts = data
})
}
})
Right now, I'm using increment and decrement operators to change the values, but no such luck.
What doesn't work is that the "Next Entry" link goes back two, and the "Previous Entry" link goes to the same id. How can I fix this? Here is a jsfiddle that I've been working on, originally from the Vue.js components tutorial.
Related
I am working on the AngularJS project and I have a page that injects a component with 3 different buttons. I need to display a hint to this button only when one of them is clicked/active/chosen (no need to display anything for another 2). I bet this should be solved with binding but I am not sure how to do it properly.
Can you advise, please?
Here is my code.
Main page HTML:
<ch-form-group
title="Which notification should be sent?"
header="Define the notification that you want to send out to the qualifying customers.">
<ch-toggle-blocks
toggle-blocks="$ctrl.event_action_params"
on-block-clicked="$ctrl.toggleEventAction(toggleBlock.key)">
</ch-toggle-blocks>
// I want to display block here. So when inside the ch-toggle-blocks user // chose only specific button
<notification-form
channel-type="$ctrl.getChannelType()"
channel="$ctrl.getChannel()">
</notification-form>
</ch-form-group>
ch-toggle-block HTML
<div class="ch-toggle-blocks">
<div
data-hook="toggle-block-selector"
class="toggle-block"
ng-click="$ctrl.clickBlock(toggleBlock)"
ng-class="{'current-toggle-block': toggleBlock.is_current}"
ng-repeat="toggleBlock in $ctrl.toggleBlocks">
<span
data-hook="current-toggle-block-label"
class="label label-cityhive"
ng-if="toggleBlock.is_current">
Current
</span>
<div class="toggle-block-icon">
<i class="{{toggleBlock.icon}}"></i>
</div>
<div class="toggle-block-name">
<span>{{toggleBlock.friendly_name}}</span>
</div>
</div>
</div>
chToggleBlocksComponent.js
'use strict';
angular.module('MyModule')
.component('chToggleBlocks', {
bindings: {
toggleBlocks: '<',
onBlockClicked: '&'
},
templateUrl: 'ch_toggle_blocks/chToggleBlocks.html',
controller: function() {
var ctrl = this;
ctrl.clickBlock = function(toggleBlock) {
this.onBlockClicked({toggleBlock: toggleBlock})
}
}
});
So, basically, when {{toggleBlock.friendly_name}} with the text "SMS" is active, I need to display another div on the main page.
I'd like to collect a variable(user _id)collected from a template, and pass it to another template using session. Then I want to display this variable.
Actually it seems to work in the collection of the variable and the pass to the other template, but I'm not able to display the user's info in the second template...
This is my code:
HTML
<template name="main"><!--Template 1-->
<table>
<tr>
<th>Patient</th>
</tr>
{{#each allUsers}}
<tr>
<th><label><input type="radio" class="selected" name="patient" value="{{this._id}}"><i class="fa fa-user"></i> {{this.profile.lastName}} {{this.profile.firstName}}</label></th>
</tr>
{{/each}}
</table>
{{>test}}
</template>
<template name="test"> <!--Template 2-->
<p>Name is <button class="test" name="patient" value="{{this._id}}">Test</button></p>
<div name="show">Name: {{this.profile.firstName}}</div>
</template>
JS
Template.main.events({
'click .selected': function (){
var selPat = $('input[name="patient"]:checked').val();
Session.set("selPat",selPat);
console.log("collect", selPat);
}
});
Template.test.events({
'click .test': function(){
var PAT= Meteor.users.findOne({ _id: Session.get("selPat")});
console.log("pass", PAT);
return PAT;
}
});
Template.patients.helpers({
allUsers: function() {
return Meteor.users.find({});
}
});
I want to display in the template 2 the first name of the user selected in the template 1 with {{this.profile.firstName}}
I believe this is what you are doing:
You are choosing patient's id from a list of patients via the radio buttons in the main template. [this implementation is correct]
You are setting the patient id in a session in the main template's events. [this implementation is correct]
When you click the "test" button in the test template, it should reveal the user's first name in the div below the button. [...not quite]
You are unable to display anything in <div name="show">Name: {{this.profile.firstName}}</div> because you don't have a relevant helper supplying the template with that information.
Although clicking a button to reveal the patient's firstName in the test template sounds a bit redundant, I'm sure you have some reason to do it in that manner.
I propose that you wrap the div inside an if block. The if condition renders true, when the button is clicked, and hence the div element is shown.
<template name="test"> <!--Template 2-->
<p>Name is <button class="test" name="patient" value="{{this._id}}">Test</button></p>
{{#if isButtonClicked}}
<div name="show">Name: {{data.profile.firstName}}</div>
{{/if}}
</template>
Your helpers and events will be like so:
Template.test.events({
'click .test': function(){
// set this session to true when the button has been clicked.
Session.set("testClicked", true);
}
});
Template.test.helpers({
isButtonClicked: function(){
// return the if block's validation.
return Session.get("testClicked");
},
data: function(){
// return the actual user data retrieved from the collection.
var PAT= Meteor.users.findOne({ _id: Session.get("selPat")});
console.log("pass", PAT);
return PAT;
});
Note:
You might want to make sure that the div does not stay open when you select a different patient from the list of radio buttons. Not doing so will make the div be visible when you first click the button, and remain open until you refresh the page, even when you select a different patient.
You could set testClicked to false or undefined in Template.main.events --> 'click .selected'
Experimenting with Vue.js, trying to display results from a Wikipedia API call in a component using the v-for directive, but something is not working on the back end and I don't know what it is.
Link to the jsFiddle
HTML
<div id="app">
<input type="text" v-model="searchTerm" v-on:keyup="getResults">
<searchResult
v-for="item in results"
v-bind:result="item"
v-bind:key="item.key"
></searchResult>
</div>
Javascript
new Vue({
el: '#app',
data: {
api: "https://en.wikipedia.org/w/api.php?",
searchTerm: 'Ron',
searchDataString: "action=opensearch&format=json&origin=*&uselang=user&errorformat=html&search="+this.searchTerm+"&namespace=0%7C4&limit=20&profile=fuzzy",
searchCall: this.api+""+this.searchDataString,
results: []
},
methods: {
getResults() {
this.searchCall = this.api+"action=opensearch&format=json&origin=*&uselang=user&errorformat=html&search="+this.searchTerm+"&namespace=0%7C4&limit=20&profile=fuzzy";
//console.log( this.searchCall );
axios.post( this.searchCall )
.then(response => { this.processResults(response.data) });
},
processResults(data) {
//console.log( data );
for(var i = 0; i < data[1].length; i++) {
var resultItem = { key:i, link:data[3][i], name:data[1], description:data[2][i] };
this.results.push(resultItem);
console.log(resultItem);
}
}
}
});
Vue.component( "searchResult", {
props:['result'],
template: "<a target='_blank' href='{{ result.link }}'><div class='search-result'><h3>{{ result.name }}</h3><p>{{ result.description }}</p><div></a>"
});
The two issues on my mind are
the error message that shows in the console when typing input, and
that the array of results is creating empty objects instead of passing the data
When I look at the array in the console, all it shows are getters and setters. I'm new to this, so maybe that's what it's supposed to be doing.
I'm so close to getting this working, but I'm at my wits end, help is much appreciated.
The problem with your code is that html tags aren't case sensitive so naming a component searchResult causes issues. If you need to use searchResult, you'll have to use <search-result> in your template. I find it better just to avoid the problem altogether and give components lower-case names. Here are docs about the issue: https://v2.vuejs.org/v2/guide/components.html#Component-Naming-Conventions
You mentioned "the error message that shows in the console when typing input". I didn't get any errors copying and pasting your code (other than forgetting to include axios). What error are you getting?
I am trying do display an element for each array inside an array and display that element if its array contains a true boolean. The if function runs the first time but the element does not disappear when the value changes.
<li v-for="(value, index) in list">
<span> {{ value[0] }} </span>
<span v-if='value[1]'> {{ value[2] }} </span>
</li>
var List = new Vue({
el: "#List",
data: {
list: ['fizz',true,0],
},
methods: {
toggleItem: function(index) {
this.list[index][1] = !this.list[index][1];
},
}
})
I should be able to run
List.toggleItem(0)
If you are updating the array in Vue then use Vue.set(); so that Vue can track the changes and update the template
for example,
Vue.set(value, 1, false);
Note: simpley updating like this value[1] = false; this will not work
For more, https://v2.vuejs.org/v2/guide/list.html#Caveats
I have some problems with angular binding and I'm not very experienced with it. I will post all questions here as they are related.
Here is some angularjs code snipped that triggers 10 digest() cycle reached. I found some similar posts and the cause is that a change is performed recursively in digest(), but I cannot find the cause in my example.
Here is code:
<work-timekeepings-day timekeepings="dailyTimekeepingCtrl.timekeepingList | timekeepingDay : dailyTimekeepingCtrl.selectedDay" day="dailyTimekeepingCtrl.selectedDay"></work-timekeepings-day>
Component:
var workTimekeepingsDay = TimekeepingsApp.component('workTimekeepingsDay', {
templateUrl : 'angular/components/work-timekeepings-day.html',
controllerAs: '$workTkDayCtrl',
bindings : {
timekeepings : '=',
day: '='
}
});
HTML template:
<div class="row lightgreen-row padding-5 border-rounded" ng-repeat-start="workTk in $workTkDayCtrl.timekeepings">
<div class="col-md-4"> <b> {{ workTk.user.firstName + ' ' + workTk.user.lastName }} </b> </div> </div> ...
Filter function:
var timekeepingDayFilter = TimekeepingsApp.filter('timekeepingDay', function() {
return function(timekeepings, filterDay) {
var result=[];
angular.forEach(timekeepings, function(timekeeping) {
var timekeepingDay = moment(timekeeping.workDay);
if (timekeepingDay.isSame(filterDay, 'day')) {
result.push(timekeeping);
}
});
return result;
}
});
If I apply filter function inside HTML template it doesn't trigger the error, but the two-way binding with 'day' variable seems to not work properly. If I update 'dailyTimekeepingCtrl.selectedDay' in another component, bound in the same way, the change is not reflected in workTimekeepingsDay component.
Here is the filter applied in component template:
<work-timekeepings-day timekeepings="dailyTimekeepingCtrl.timekeepingList" day="dailyTimekeepingCtrl.selectedDay"></work-timekeepings-day>
<div class="row lightgreen-row padding-5 border-rounded" ng-repeat-start="workTk in $workTkDayCtrl.timekeepings | timekeepingDay : day">
<div class="col-md-4"> <b> {{ workTk.user.firstName + ' ' + workTk.user.lastName }} </b> </div> </div> ..
Q1: Why is the 'digest() aborted' error occur if I am not updating the base array? How can I pass directly the filtered array to component in timekeepings variable?
Q2: Why is day variable not updated in component if dailyTimekeepingCtrl.selectedDay is updated?
I solved this by using lodash memoize function to use result from cash. Although I'd have preferred to not use an external library, but to change the algorithm, I am still happy with this.