Vuejs component does not render immediately - html

I have a vue app and a component. The app simply takes input and changes a name displayed below, and when someone changes the name, the previous name is saved in an array. I have a custom component to display the different list items. However, the component list items do not render immediately. Instead, the component otems render as soon as I type a letter into the input. What gives? Why would this not render the list items immediately?
(function(){
var app = new Vue({
el: '#app',
components: ['name-list-item'],
data: {
input: '',
person: undefined,
previousNames: ['Ian Smith', 'Adam Smith', 'Felicia Jones']
},
computed: {
politePerson: function(){
if(!this.person) {
return 'Input name here';
}
return "Hello! To The Venerable " + this.person +", Esq."
}
},
methods: {
saveInput: function(event){
event.preventDefault();
if(this.person && this.previousNames.indexOf(this.person) === -1) {
this.previousNames.push(this.person);
}
this.setPerson(this.input);
this.clearInput();
},
returnKey: function(key) {
return (key + 1) + ". ";
},
clearInput: function() {
this.input = '';
},
setPerson: function(person) {
this.person = person;
}
}
});
Vue.component('name-list-item', {
props: ['theKey', 'theValue'],
template: '<span>{{theKey}} {{theValue}}</span>'
});
})()
And here is my HTML.
<div id="app">
<div class="panel-one">
<span>Enter your name:</span>
<form v-on:submit="saveInput">
<input v-model="input"/>
<button #click="saveInput">Save</button>
</form>
<h1>{{politePerson}}</h1>
</div>
<div class="panel-two">
<h3>Previous Names</h3>
<div>
<div v-for="person, key in previousNames" #click='setPerson(person)'><name-list-item v-bind:the-key="key" v-bind:the-value="person" /></div>
</div>
</div>
</div>

You are not defining your component until after you have instantiated your Vue, so it doesn't apply the component until the first update.

Related

Vue v-model on input as a dynamic ref

I created this <input> Vue component that handles a v-model property.
Adding the two-way data binding wasn't a problem, but I now want to add the current input value to the "state" so that I can clear it by just modifying a ref.
clearValue is called as expected but updating inputValue doesn't update the UI. What should I be doing differently ?
<template>
<div>
<input
:id="id"
type="text"
:value="inputValue"
#input="updateValue"
/>
<UiIcon
type="x"
#click.native="clearValue"
/>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, ref } from '#nuxtjs/composition-api';
import UiIcon from '~/components/ui/UiIcon.vue';
export default defineComponent({
name: 'UiInput',
components: { UiIcon },
props: {
id: {
type: String,
required: true,
},
value: {
type: String,
default: undefined,
},
},
setup(props, { emit }) {
const inputValue = ref(props.value);
const clearValue = () => {
inputValue.value = '';
};
const updateValue = (event: Event) => {
emit('input', (event.target as HTMLInputElement).value);
};
return {
updateValue,
clearValue,
inputValue,
};
},
});
Usage example
data() {
return { text: '' };
},
template: `
<div>
<UiInput :id="id" v-model="text" />
</div>
`,
I think you just need to emit 'input' event with empty value inside clearValue function
emit('input', '');

Vue.js - Search function for JSON Object

I am new to Vue.js, and I want to add a search function for my site. The data is from an API Call and is displayed using vue.js too.
Display HTML Code:
<div class="row" v-for="items in data">
<div class="col-lg-4 col-md-6" data-toggle="modal" data-target="#exampleModal" user="'items'" #click="sendInfo(items)">
<a href="#" class="latest-product__item">
<div class="latest-product__item__pic">
<img src="img/item_image_placeholder.jpg" alt="">
</div>
<div class="latest-product__item__text">
<h6>{{items.item_name}}</h6>
<div v-for="variant in items.variants">
<div v-for="store in variant.stores">
<span>{{store.default_price}}</span>
</div>
</div>
</div>
</a>
</div>
And here's my Vue.js:
window.onload = function () {
const access_token = "";
new Vue({
el: '#item-data',
data () {
return {
data:[],
selectedUser:'',
itemCart: [],
search:'',
quantity: '',
cartCheckout: []
}
},
mounted () {
axios.get('**api call here**', {
headers : {
Authorization: 'Bearer ' + access_token
},
params: {
limit: 250
}
})
.then((response) => {
// handle success
this.data = response.data.items
console.log(response);
removeLoader();
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
});
},
computed:{
cartItem(){
return store.getters.printCart;
},
count(){
return store.state.cartCount;
},
},
methods:{
sendInfo(items) {
this.selectedUser = items;
},
addCart: function(cartdets){
store.commit('addCart', cartdets);
store.commit('addCount', 1);
}
}
})
}
What I want now is to add a search function to my displayed items. I already added v-model to my input tag. The items are dynamically displayed using vue and I want a search function for specific items.
You could create a computed property, maybe name it something like filteredItems, and make it loop through all of your items and save the items you want to display into an array and then return that array.
Then in your html use a v-for to display the items from filteredItems.

On button click clear displayed text and call another function in VueJs

I'm fairly new to web development and vue.js.
I have an app where I enter an Id in and on button(search) click it is calling a method. This method makes an axios call to the controller and retrieves data as an object.
This data is displayed in tag (not sure if this approach is correct).
After this data is displayed, when the second time I enter another Id in the field and hit the button, it still displays the old text till it fetches the new data. Once new data is retrieved, it displays the new one.
I want to clear this data everytime I hit the button for search as well as call the vue function to fetch data.
I have tried clearing the data at the beginning of the vue function call but that didn't work.
<input type="text" placeholder="Enter the ID" v-model="mId" />
<button type="button" class="searchgray" v-on:click="SubmitId">Search</button>
<h4 style="display: inline">ID: {{queryData.Id}}</h4>
<strong>Device Status: </strong><span>{{queryData.deviceStatus}}</span>
<script>
export default {
components: {
'slider': Slider,
Slide
},
props:['showMod'],
data() {
return {
mId '',
queryData: {},
}
},
methods: {
SubmitId: function () {
this.queryData = {}
axios.get('/Home/SearchId?Id=' + this.mId)
.then(response => response.data).then(data => {
this.queryData = data
}).catch(err => {
this.queryData = {}
this.mId = ''
alert(`No records found anywhere for the given mId`)
});
}
}
</script>
So in the above code, when I hit the Search button, it calls the SubmitId function and returns queryData. Now when I enter a new mId in input field and hit serach button it continues to display the querydata associated with the old mId till the fetching of data is completed and new query data for the new mId is returned.
I was looking for a way to clear the screen text everytime I hit the button. So I also tried doing queryData={} before the axios call, but it didn't help.
Help appreciated.
new Vue({
el: '#app',
props: [
'showMod'
],
data() {
return {
mId: '',
queryData: {}
}
},
methods: {
async SubmitId () {
const axiosRequest = () => new Promise((resolve, reject) => {
const obj = {
Id: Math.random(),
deviceStatus: Math.random()
}
setTimeout(() => {
resolve(obj)
// reject('Not Found')
}, 2000)
})
try {
this.queryData = {}
this.queryData = await axiosRequest()
} catch (err) {
this.mId = ''
alert('No records found anywhere for the given mId')
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input
v-model="mId"
type="text"
placeholder="Enter the ID"
/>
<button
v-on:click="SubmitId"
type="button"
class="searchgray"
>
Search
</button>
</br>
<h4 style="display: inline">
ID: {{ queryData.Id }}
</h4>
</br>
<strong>Device Status: </strong>
<span>{{ queryData.deviceStatus }}</span>
</div>

Change values in a static template

Here is a basic setup for what I would like to do:
HTML Side
test.html
<div id="app">
<my-comp temp="1" cat="{ name:'Geoff', age:3 }"></my-comp>
</div>
Vue Side
app.js:
import myComp from './components/myComp.vue'
app = new Vue({
el: "#app",
components: {
myComp
}
});
myComp.vue
<template>
<div v-html='template'>
</div>
</template>
<script>
export default {
props: [
'temp',
'cat'
],
data () {
temp1: `<input name="name" value="cat.name">
<input name="age" value="cat.age">`,
// other template
// ...
},
computed: {
template() {
return this.temp == 1 ? this.temp1 : this.temp2;
}
}
}
</script>
My problem is when I open the html file in the browser, I get:
cat.name
cat.age
appearing in the input. Technically, my form isn't responsive to existing data. How can I solve this?
In your test.html you have to change this:
<my-comp :temp="1" :cat="{ name:'Geoff', age:3 }"></my-comp>
The double dots have to added otherwise it will be interpreted as an string and not as an object.
With value you are on the right track. The only you have to change is this because you want to insert a variable into your 'string'
data() {
return {
temp1: `<input name="name" value="${this.cat.name}">
<input name="age" value="${this.cat.age}">`
}
}
Don't forget to add 'input type' as well.

"[object object]" shown when double-clicking input

Below is the template I am using for the directive. In code we are
fetching the data from a service in that data we have all the
information of that particular person. And from that data we are
showing only first name, last name and designtion or company
affiliation.
<div ng-if="model" class="entry-added">
<span class="form-control"><b>{{model.fullName}}</b>, <br/><span class="small-font">{{(model.designation)?model.designation:model.companyAffiliation}}</span></span>
<a ng-click="removePerson()" class="action-remove"><i class="fa fa-remove"></i></a>
</div>
<div ng-show="!model" class="input-group">
<input type="text"
class="form-control"
name="{{name}}"
id="{{name}}"
placeholder="{{placeholder}}"
ng-required="{{isRequired}}"
typeahead-on-select = "change($item, $model, $label)"
ng-model="model"
typeahead-min-length="3",
typeahead="suggestion for suggestion in searchEmployees($viewValue)"
typeahead-template-url="typeAheadTemplate.html"
typeahead-loading="searching"
typeahead-editable="false">
<script type="text/ng-template" id="typeAheadTemplate.html">
<a class="ui-corner-all dropdown" tabindex="-1">
<div class="col-md-2"><img class="dropdown-image" ng-src="https://people.***.com/Photos?empno={{match.model.employeeNumber}}"></div>
<div>
<div bind-html-unsafe="match.model.fullName"></div>
<div bind-html-unsafe="match.model.designation"></div>
</div>
</a>
</script>
I am using a custom directive to display a search field. The drop down is displaying [object object].
Directive
// In backend taxDeptContact is a Person type object
/*
Directive code
*/
(function () {
'use strict';
angular.module('treasuryApp.directives').directive('employeeSearch', employeeSearch);
employeeSearch.$inject = ['$resource', '$rootScope', 'ErrorHandler'];
function employeeSearch($resource, $rootScope, ErrorHandler) {
return {
restrict: 'E',
require: '^form',
scope: {
model: "=",
isRequired: '#',
submitted: "=",
onSelect: '&',
name: '#',
index:'#'
},
link: function(scope, el, attrs, formCtrl) {
//set required attribute for dynamically changing validations
scope.searchEmployees = function (searchTerm) {
var users = [];
var myResult = [];
var result = $resource($rootScope.REST_URL + "/user/getEmployees", {term: searchTerm}).query().$promise.then(function (value) {
//console.log(value)
$.each(value, function(i, o) {
users.push(o);
});
return users;
});
return result;
}
scope.removePerson = function() {
scope.model=null;
}
scope.userNotSelectedFromTypeahead = function(name) {
if(undefined === formCtrl[name]) {
return false;
}
return formCtrl[name].$error.editable;
};
scope.change = function(item, model, label) {
scope.model = item
scope.onSelect(
{name: scope.name, person: scope.model});
},
templateUrl: 'app/components/common/directives/employee-search.tpl.html'
};
}
})();
View that is using the directive
<div class="form-group">
<label class="col-sm-3>Tax Dept Contact</label>
<div class="col-sm-4">
<employee-search model="reqCtrl.requestObj.taxDepartmentContact" name="taxDeptContact" is-required="false" submitted="reqCtrl.submitted"/>
</div>
</div>
Image of the error occuring
Looks like this may be your trouble spot
typeahead="suggestion for suggestion in searchEmployees($viewValue)"
suggestion for suggestion is pulling the whole object. Have you tried displaying a particular attribute of suggestion?
For example: if you had a suggestion.name attribute you would write:
typeahead="suggestion.name for suggestion in searchEmployees($viewValue)"
Finally got the answer: I used autocomplete="off" in my directive and thats all
<input type="text" autocomplete="off" />