I'm using the Typeahead component from vue-strap,
Am trying to make a callback after i hit on the selection which will stamp the data into my input texts.
Once i hit enter, inventoryName and inventoryId is successfully stamped in but the inventoryCode component is reset.
How to prevent it from reset or did i do anything wrong? As i can see from console.log it has the value.
<typeahead v-model="inventoryCode" placeholder="Inventory code..." async="{{url('api/inventory')}}/" :template="inventorySearch" :on-hit="inventoryCallBack"></typeahead>
<input type="text" name="inventory_name" id="inventory_name" class="form-control" v-model="inventoryName" readonly />
new Vue({
el: '#app',
components:{Typeahead},
data: {
'inventoryCode': '',
'inventoryName': '',
'inventoryId': '',
'inventorySearch': '<div style="min-width:150px;"><b>#{{item.inventory_name}}</b></div><div>#{{item.inventory_code}}</div><div>#{{item.inventory_short_desc}}</div>'
},
methods:{
inventoryCallBack: function(item){
console.log(item.inventory_code);
this.inventoryCode = item.inventory_code;
this.inventoryName = item.inventory_name;
this.inventoryId = item.id;
console.log(this.inventoryCode);
},
}
});
inventoryCallBack: function(item){
console.log(item.inventory_code);
this.inventoryCode = item.inventory_code;
this.inventoryName = item.inventory_name;
this.inventoryId = item.id;
return item.inventory_code
},
This should do the trick, missed out this part.
Related
I'm making a discussion forum and I want to remove the users ability to edit the comment they made after 30 mins.
This is the code for my button in the vue.js, it's not a "real" button, it's a clickable icon
<div class="btn-link-edit action-button"
#click="edit(comment)">
<i class="fas fa-pencil-alt"></i>
</div>
method in vue.js
edit(model) {
this.mode = 'Editar';
this.form = _.cloneDeep(model);
this.dialogFormVisible = true;
},
What would be the best way to add this timer, the timer should start right when the user makes the comment, in the table for this I have a field called comment_time with that information.
How can I do this?
The simplest way to do that is:
Here in template:
<div id="app">
<div v-for="comment in comments">
<p>
{{comment.text}}
</p>
<button v-if="commentTime(comment.comment_time)">Edit </button>
</div>
</div>
Vue script:
new Vue({
el: "#app",
data: {
comments: [
{ text: "Nancy comment", comment_time: 1579206552201}
]
},
computed: {
now () {
return new Date()
}
},
methods: {
commentTime(cTime){
let t = new Date(cTime)
t.setMinutes(t.getMinutes() + 30)
return this.now.getTime() < t.getTime()
}
}
})
You can show the result here:
your code in jsfiddle
First, start by putting v-if="canEdit" on your <div>. Then in your script section of the Vue component we're going to create a canEdit boolean, then a loop to update it on a regular basis. This assumes you have a specific Comment.vue component and this.comment is being passed to the component already, maybe as a prop or something, and that it contains the typical Laravel Model fields, specifically created_at.
data() {
return {
canEdit: true, // Defaults to `true`
checkTimer: null, // Set the value in `data` to help prevent a memory leak
createdAt: new Date(this.comment.created_at),
};
},
// When we first make the component, we set `this.createdPlus30`, then create the timer that checks it on a regular interval.
created() {
this.checkTimer = setInterval(() => {
this.canEdit = new Date() > new Date(this.created_at.getTime() + 30*60000);
}, 10000); // Checks every 10 seconds. Change to whatever you want
},
// This is a good practice whenever you create an interval timer, otherwise it can create a memory leak.
beforeDestroy() {
clearInterval(this.checkTimer);
},
So I've made update function for my component and it's working perfectly the only issue is I cannot show old data (if there is any) to the user,
This is what I have now:
As you see not only i can send my form data to back-end for update, but also I have the saved data already.
Code
export default {
data: function () {
return {
info: '', //getting data from database
profile: { //sending new data to back-end
photo: '',
about: '',
website: '',
phone: '',
state: '',
city: '',
user_id: '',
csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
}
}
},
mounted: function() {
this.isLoggedIn = localStorage.getItem('testApp.jwt') != null;
this.getInfo();
},
beforeMount(){
if (localStorage.getItem('testApp.jwt') != null) {
this.user = JSON.parse(localStorage.getItem('testApp.user'))
axios.defaults.headers.common['Content-Type'] = 'application/json'
axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('testApp.jwt');
console.log()
}
},
methods: {
update() { // sending data to back-end
let user_id = this.user.id;
let photo = this.profile.photo;
let about = this.profile.about;
let website = this.profile.website;
let phone = this.profile.phone;
let state = this.profile.state;
let city = this.profile.city;
axios.put('/api/updateprofile/'+ user_id, {user_id, photo, about, website, phone, state, city}).then((response) => {
this.$router.push('/profile');
$(".msg").append('<div class="alert alert-success" role="alert">Your profile updated successfully.</div>').delay(1000).fadeOut(2000);
});
Vue.nextTick(function () {
$('[data-toggle="tooltip"]').tooltip();
})
},
getInfo: function() { //getting current data from database
let user_id = this.user.id;
axios.get('/api/show/'+ user_id).then((response) => {
this.info = response.data;
console.log(response);
});
},
}
}
Component sample field
// this shows my about column from database
{{info.about}}
// this sends new data to replace about column
<textarea name="about" id="about" cols="30" rows="10" class="form-control" v-model="profile.about" placeholder="Tentang saya..."></textarea>
Question
How to pass old data to my fields (sample above)?
Update
Please open image in big size.
This can be done by assigning this.profile the value of this.info on your Ajax response.
This way you will have input fields set up with original values.
function callMe() {
var vm = new Vue({
el: '#root',
data: {
profile:{},
info:{}
},
methods: {
getInfo: function() { //getting current data from database
this.info={about:"old data"}//your response here
this.profile=Object.assign({},this.info);
},
},
})
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.11/dist/vue.js"></script>
<div id='root'>
<button #click="getInfo">Ajax Call click me</button>
Input <input v-model="profile.about"/>
<p>profile:{{this.profile}}</p>
<p>info: {{this.info}}</p>
</div>
The problem with the code is that after assigning new value info is not reactive anymore. You need to keep "info" like this in the start.
info: { // data from api
photo: '',
about: '',
website: '',
phone: '',
state: '',
city: '',
user_id: '',
}
And after fetching values from api update each value separately.
getInfo: function() { //getting current data from database
let user_id = this.user.id;
axios.get('/api/show/'+ user_id).then((response) => {
this.info.photo = response.data.photo;
this.info.about = response.data.about;
//all other values
console.log(response);
});
},
In your textarea you have a model profile.about, the way to show the "old data", is to assing to that model the data
in the create or mounted method you have to assing like
this.profile.about = this.info.about
this way profile.about will have the data stored in your db, that way if the user update it, the old data will be keep safe in this.info.about and the edited in this.profile.about
I have created datepicker vuejs component.
I have set two date picker in page to select start date and end date. So startDate and endDate of one datepicker is depend on value of another. So for that, I need to set watcher on selected value.
It was working fine with VueJS (< 2.3.0) using this.$emit('input', value). But in VueJS (2.4.4), it is not working.
I'm very poor in front-end development. So I got nothing even after spending two days on vuejs. I just come to know that it is just because of vue version > 2.2.6.
If anyone know the solution, it will be realy very much helpful for me.
Here is my code.
DatePicker.vue
<template>
<div class="input-append date form_datetime">
<input size="16" type="text" readonly>
<span class="add-on"><i class="icon-th fa fa-calendar"></i></span>
</div>
</template>
<script>
export default {
twoWay: true,
props: ['slctd', 'startDate', 'endDate'],
mounted: function () {
var self = this;
$(this.$el).datetimepicker({
format: "mm/dd/yyyy",
autoclose: true,
minView: 2,
maxView: 3,
daysShort: true,
initialDate: this.slctd,
startDate: this.startDate,
endDate: this.endDate,
}).on('changeDate', function (ev) {
var value = new Date(ev.date.valueOf()).toString('MM/dd/yyyy');
self.$emit('input', value);
});
},
watch: {
slctd: function (value) {
console.log('watch:value ' + value);
$(this.$el).find("input").val(value);
},
startDate: function (value) {
console.log('watch:start ' + value);
$(this.$el).datetimepicker('setStartDate', value);
},
endDate: function (value) {
console.log('watch:end ' + value);
$(this.$el).datetimepicker('setEndDate', value);
}
},
}
</script>
JS
window.Vue = require('vue');
Vue.component('component-date-picker', require('./components/DatePicker.vue'));
window.app = new Vue({
el: '#app',
data: {
queries: {
start_date: '10/04/2017',
end_date: '10/05/2017',
}
},
});
HTML
<component-date-picker v-bind:end-date="queries.end_date" v-bind:slctd="queries.start_date" v-model="queries.start_date"></component-date-picker>
<component-date-picker v-bind:start-date="queries.start_date" v-bind:slctd="queries.end_date" v-model="queries.end_date"></component-date-picker>
VueJS - 2.2.6 (working)
VueJS - 2.4.4 (not working)
I have also tried this too. But didn't get success
HTML
<component-date-picker v-bind:end-date="queries.end_date" v-bind:slctd="queries.start_date" v-model="queries.start_date" v-on:input="set_start_date"></component-date-picker>
<component-date-picker v-bind:start-date="queries.start_date" v-bind:slctd="queries.end_date" v-model="queries.end_date" v-on:input="set_end_date"></component-date-picker>
JS
methods: {
set_start_date: function(value){
console.log('called');
this.queries.start_date = value;
},
set_end_date: function(value){
this.queries.end_date = value;
},
}
In this code, I method was called and I was getting 'called' in console. But watcher of component not working. It should work as startDate/endDate is changed in these methods. I don't know what is the new working concept of VueJS 2.4.4.
Solved
It was my stupid mistake due to lack of knowledge in front-end. I was re-creating queries object in create method of vue root instance. And in previous code, there was nothing in create so it was working fine.
Here is my mistake
JS
created: function () {
/* my mistake starts */
this.queries = queryString.parse(location.search, {arrayFormat: 'bracket'});
/* my mistake ends */
this.queries.start_date = (this.queries.start_date) ? this.queries.start_date : null;
this.queries.end_date = (this.queries.end_date) ? this.queries.end_date : null;
},
I'm working on a project that is using Vue.js and Vue Router as the frontend javascript framework that will need to use a select box of users many places throughout the app. I would like to use select2 for the select box. To try to make my code the cleanest I can, I've implemented a custom filter to format the data the way select2 will accept it, and then I've implemented a custom directive similar to the one found on the Vue.js website.
When the app starts up, it queries the api for the list of users and then stores the list for later use. I can then reference the users list throughout the rest of the application and from any route without querying the backend again. I can successfully retrieve the list of users, pass it through the user list filter to format it the way that select2 wants, and then create a select2 with the list of users set as the options.
But this works only if the route that has the select2 is not the first page to load with the app. For example, if I got to the Home page (without any select2 list of users) and then go to the Users page (with a select2), it works great. But if I go directly to the Users page, the select2 will not have any options. I imagine this is because as Vue is loading up, it sends a GET request back to the server for the list of users and before it gets a response back, it will continues with its async execution and creates the select2 without any options, but then once the list of users comes back from the server, Vue doesn't know how to update the select2 with the list of options.
Here is my question: How can I retrieve the options from an AJAX call (which should be made only once for the entire app, no matter how many times a user select box is shown) and then load them into the select2 even if the one goes directly to the page with the select2 on it?
Thank you in advance! If you notice anything else I should be doing, please tell me as I would like this code to use best practices.
Here is what I have so far:
Simplified app.js
var App = Vue.extend({
ready: function() {
this.fetchUsers();
},
data: function() {
return {
globals: {
users: {
data: []
},
}
};
},
methods: {
fetchUsers: function() {
this.$http.get('./api/v1/users/list', function(data, status, response) {
this.globals.users = data;
});
},
}
});
Sample response from API
{
"data": [
{
"id": 1,
"first_name": "John",
"last_name": "Smith",
"active": 1
},
{
"id": 2,
"first_name": "Emily",
"last_name": "Johnson",
"active": 1
}
]
}
User List Filter
Vue.filter('userList', function (users) {
if (users.length == 0) {
return [];
}
var userList = [
{
text : "Active Users",
children : [
// { id : 0, text : "Item One" }, // example
]
},
{
text : "Inactive Users",
children : []
}
];
$.each( users, function( key, user ) {
var option = { id : user.id, text : user.first_name + ' ' + user.last_name };
if (user.active == 1) {
userList[0].children.push(option);
}
else {
userList[1].children.push(option);
}
});
return userList;
});
Custom Select2 Directive (Similar to this)
Vue.directive('select', {
twoWay: true,
bind: function () {
},
update: function (value) {
var optionsData
// retrive the value of the options attribute
var optionsExpression = this.el.getAttribute('options')
if (optionsExpression) {
// if the value is present, evaluate the dynamic data
// using vm.$eval here so that it supports filters too
optionsData = this.vm.$eval(optionsExpression)
}
var self = this
var select2 = $(this.el)
.select2({
data: optionsData
})
.on('change', function () {
// sync the data to the vm on change.
// `self` is the directive instance
// `this` points to the <select> element
self.set(select2.val());
console.log('emitting "select2-change"');
self.vm.$emit('select2-change');
})
// sync vm data change to select2
$(this.el).val(value).trigger('change')
},
unbind: function () {
// don't forget to teardown listeners and stuff.
$(this.el).off().select2('destroy')
}
})
Sample Implementation of Select2 From Template
<select
multiple="multiple"
style="width: 100%"
v-select="criteria.user_ids"
options="globals.users.data | userList"
>
</select>
I may have found something that works alright, although I'm not sure it's the best way to go about it. Here is my updated code:
Implementation of Select2 From Template
<select
multiple="multiple"
style="width: 100%"
v-select="criteria.reporting_type_ids"
options="globals.types.data | typeList 'reporttoauthorities'"
class="select2-users"
>
</select>
Excerpt from app.js
fetchUsers: function() {
this.$http.get('./api/v1/users/list', function(data, status, response) {
this.globals.users = data;
this.$nextTick(function () {
var optionsData = this.$eval('globals.users.data | userList');
console.log('optionsData', optionsData);
$('.select2-users').select2({
data: optionsData
});
});
});
},
This way works for me, but it still kinda feels hackish. If anybody has any other advice on how to do this, I would greatly appreciate it!
Thanks but I'm working on company legacy project, due to low version of select2, I encountered this issue. And I am not sure about the v-select syntax is from vue standard or not(maybe from the vue-select libaray?). So here's my implementation based on yours. Using input tag instead of select tag, and v-model for v-select. It works like a charm, thanks again #bakerstreetsystems
<input type="text"
multiple="multiple"
style="width: 300px"
v-model="supplier_id"
options="suppliers"
id="select2-suppliers"
>
</input>
<script>
$('#app').ready(function() {
var app = new Vue({
el: "#app",
data: {
supplier_id: '<%= #supplier_id %>', // We are using server rendering(ruby on rails)
suppliers: [],
},
ready: function() {
this.fetchSuppliers();
},
methods: {
fetchSuppliers: function() {
var self = this;
$.ajax({
url: '/admin_sales/suppliers',
method: 'GET',
success: function(res) {
self.suppliers = res.data;
self.$nextTick(function () {
var optionsData = self.suppliers;
$('#select2-suppliers').select2({
placeholder: "Select a supplier",
allowClear: true,
data: optionsData,
});
});
}
});
},
},
});
})
</script>
Im just trying to delete a model from a collection, with a link on itself.
I've attach the event to the "Eliminar button" but it seems Im losing the reference to the model element that contains it... and can't find it.. can you?:
(function ($) {
//Model
Pelicula = Backbone.Model.extend({
name: "nulo",
link: "#",
description:"nulo"
});
//Colection
Peliculas = Backbone.Collection.extend({
initialize: function (models, options) {
this.bind("add", options.view.addPeliculaLi);
this.bind("remove", options.view.delPeliculaLi);
}
});
//View
AppView = Backbone.View.extend({
el: $("body"),
initialize: function () {
this.peliculas = new Peliculas( null, { view: this });
//here I add a couple of models
this.peliculas.add([
{name: "Flying Dutchman", link:"#", description:"xxxxxxxxxxxx"},
{name: "Black Pearl", link: "#", description:"yyyyyyyyyyyyyy"}
])
},
events: {"click #add-movie":"addPelicula", "click .eliminar":"delPelicula"},
addPelicula: function () {
var pelicula_name = $("#movieName").val();
var pelicula_desc = $("#movieDesc").val();
var pelicula_model = new Pelicula({ name: pelicula_name },{ description: pelicula_desc });
this.peliculas.add( pelicula_model );
},
addPeliculaLi: function (model) {
var str= model.get('name').replace(/\s+/g, '');
elId = str.toLowerCase();
$("#movies-list").append("<li id="+ elId +"> " + model.get('name') + " <a class='eliminar' href='#'>Eliminar</a> </li>");
},
delPelicula: function (model) {
this.peliculas.remove();
console.log("now should be triggered the -delPeliculaLi- event bind in the collection")
},
delPeliculaLi: function (model) {
console.log(model.get('name'));
$("#movies-list").remove(elId);
}
});
var appview = new AppView;
})(jQuery);
And my html is:
<div id="addMovie">
<input id="movieName" type="text" value="Movie Name">
<input id="movieDesc" type="text" value="Movie Description">
<button id="add-movie">Add Movie</button>
</div>
<div id="lasMovies">
<ul id="movies-list"></ul>
</div>
There are several things in this code that won't work. Your major problem here is that you don't tell your collection which model to remove. So in your html you have to assign so unique id that later will identify your model.
// set cid as el id its unique in your collection and automatically generated by collection
addPeliculaLi: function (model) {
$("#movies-list").append("<li id="+ model.cid +"> <a href="+ model.get('link')+">" +
model.get('name') + "</a> <a class='eliminar' href='#'>Eliminar</a> </li>"
);
},
// fetch and delete the model by cid, the callback contains the jQuery delete event
delPelicula: function (event) {
var modelId = this.$(event.currentTarget).attr('id');
var model = this.peliculas.getByCid(modelId);
this.peliculas.remove(model);
// now the remove event should fire
},
// remove the li el fetched by id
delPeliculaLi: function (model) {
this.$('#' + model.cid).remove();
}
If there aren't other errors that I have overlooked your code should work now. This is just a quick fix. Maybe you should have a look at the todos example of Backbone to get some patterns how to structure your app.
http://documentcloud.github.com/backbone/examples/todos/index.html