Check if value exists in vuejs - vue.js

I have data : 1,2,3,4,4,5 & my code like this:
<div id="looping" v-for="display in editlistAssesments">
{{display.test_id}}
</div>
My code if in php such as like this
$temp_id = array();
foreach($data as $data){
if(in_array($data ->test_id,$temp_id)){
echo" 1: no";
echo" 2: no";
echo" 3: no";
echo" 4: yes"; //because he have same value
echo" 5: no";
$temp_id[] = $data ->test_id;
}
}
how I can do that in loop vueJs..??

From my point of view, the best way is:
<div id="looping"
v-for="display in editlistAssesments">
<span v-if="typeof display.test_id !== 'undefined'">
{{display.test_id}}
</span>
</div>
Because if you use v-if="display.test_id" and the test_id value is 0 (boolean comparation) you will never see the display.text_id.
You can use also this another condition to check if is null or undefined: display.test_id != null (loose equality operator)

As far as I understand, you want to check if value is in array and then render it accordingly?
If so, you need a Vue custom filter. Something like this will do the trick:
var vm = new Vue({
el: 'body',
data: {
editlistAssesments: [1,2,3,4,4,5]
},
filters: {
ifInArray: function (value) {
return this.editlistAssesments.indexOf(value) > -1 ? 'Yes' : 'No';
}
},
});
And then use it like this:
<div id="looping" v-for="display in editlistAssesments">
<span v-text="display.test_id | ifInArray"></span>
<!-- bind Vue value to html element is better practice -->
</div>
Check docs for more information:
http://vuejs.org/guide/custom-filter.html

Related

Vue Element Table: undefined nested value crashes Chrome

I'm using a Vue Element table to display a list of objects that has an object nested in it.
"main_list":{
"id": "1",
"user": {
"username": "Bob"
}
}
I can display the username using:
<el-table-column prop="user.username" label="User" sortable />
Every now and then this page will throw an error stating that it can not read value username of undefined. This will crash Google Chrome to the extent that you have to kill all Chrome processes in the task manager. Firefox does not crash this bad. I think it goes into an infinite loop
I get the data via API, so it might be that some of the user object does not have any usernames.
So far the the only solution that I have found (I'm not sure it is a solution) is:
<el-table-column prop="username" label="User">
<template
v-if="typeof scope.row.assigned_to !== 'undefined'"
slot-scope="scope"
>{{ scope.row.assigned_to.username }}</template>
</el-table-column>
Do you have any Idea why this crash happens?
Is there a better solution than mine?
Once you fetch the list of items, you should update each one of them so that every user has a defined username - even if it is an empty string. Something like
axios.get(url).then(result =>
this.items = result.data.map(item =>
{
if(!item.user) item.user = {};
if(!item.user.username) item.user.username = '';
return item;
});
You can also try something else:
<el-table-column label="User" sortable :sort-method="sortUsers">
<template slot-scope="tbl">
{{ (tbl.row.user || {}).username || 'UNKNOWN' }}
</template>
</el-table-column>
methods:
{
sortUsers(a, b)
{
const left = (a.user || {}).username || 'UNKNOWN';
const right = (b.user || {}).username || 'UNKNOWN';
if (left < right) return -1;
if (left > right) return 1;
return 0;
}
}

Dynamically Tally Child Elements by Classname in Vue

I have a page that allows a user to drag/drop images into pre-defined DIVs, then I tally up the total value of the images based on their class name. What I am trying to do is get vue to read the values from each outer div.answer and get the class names of the child images.
My source code is:
<div
is="box-answers"
v-for="box in boxes.slice().reverse()"
v-bind:key="box.id"
v-bind:level="box.level"
v-bind:hint="box.hint"
></div>
<script>
Vue.component('box-answers', {
props: ['level','hint'],
template: '<div class="droppable answer :id="level" :title="hint"></div>'
});
new Vue({
el: '#mainapp',
data: {
boxes: [
{ id: 1, level: 'baselevel-1', hint: 'x 1' },
{ id: 2, level: 'baselevel-2', hint: 'x 20' },
{ id: 3, level: 'baselevel-3', hint: 'x 400' },
{ id: 4, level: 'baselevel-4', hint: 'x 8,000' },
{ id: 5, level: 'baselevel-5', hint: 'x 160,000' }
]
}
</script>
This converts to the follow HTML (the nested DIVs and SPANs are user-possible entries by dragging):
<div id="baselevel-5" class="droppable answer" title="x 160,000">
<div><img src="images/line.gif" alt="Five" class="imgfive"></div>
<span><img src="images/dot.gif" alt="One" class="imgone"></span>
</div>
...
<div id="baselevel-1" class="droppable answer" title="x 1">
<span><img src="images/line.gif" alt="One" class="imgone"></span>
</div>
Currently, I have jQuery/JavaScript calculating the point values using the following:
$(function(j) {
var arAnswers = Array(1);
count = 0; //
j("div.answer").each(function( idx ) {
currentId = j(this).attr('id');
ones = 0;
fives = 0;
if ( j("#" + currentId).children().length > 0 ) {
ones = j("#" + currentId).children().find("img.imgone").length * 1;
fives = j("#" + currentId).children().find("img.imgfive").length * 5;
arAnswers[count] = ones + fives; //Tally box value
count++;
}
});
});
I would like Vue to perform similar iteration and addition to return total value of ones and fives found based on the image classname.
Currently, you are approaching this problem as a pure-play DOM operation. If that is what you need then you can simply use $refs:
<!-- NOTICE ref -->
<div ref="boxAnswers"
is="box-answers"
v-for="box in boxes.slice().reverse()"
v-bind:key="box.id"
v-bind:level="box.level"
v-bind:hint="box.hint">
</div>
Inside your high-level component, you will have a function like:
function calculate() {
// NOTICE $refs
const arAnswers = this.$refs.boxAnswers.map((x) => {
// $el is the DOM element
const once = x.$el.querySelectorAll('img.imgone').length * 1;
const fives = x.$el.querySelectorAll('img.imgfive').length * 5;
return once + fives
});
return arAnswers;
}
But this is not the correct Vue way of doing things. You have to think in terms of events and data model (MVVM - don't touch DOM. DOM is just a representation of your data model). Since, you have a drag-n-drop based application, you have to listen for drag, dragstart, dragend and other drag events. For example:
<!-- NOTICE drop event -->
<div #drop="onDropEnd(box, $event)"
is="box-answers"
v-for="box in boxes.slice().reverse()"
v-bind:key="box.id"
v-bind:level="box.level"
v-bind:hint="box.hint">
</div>
Your onDropEnd event handler will look like:
function onDrop(box, $event) {
// box - on which box drop is happening
// $event.data - which image is being dropped
// Verify $event.data is actually the image you are intending
if ($event.data === 'some-type-image') {
// Do the counting manipulations here
// ... remaining code
}
}
This is not a complete code as I don't know other components. But it should help you with the required direction.

Vue v-for changing from version 1 to version 2

I'm learning Vue.js and found this fiddle that does exactly what I want to do.
Here is the fiddle: https://jsfiddle.net/os7hp1cy/48/
I integrated this and am getting this error:
invalid expression: v-for="user in users | filterBy searchKey | paginate"
So I've done some digging and I see it has changed from version 1 to 2. However, I don't know how to fix this.
<li v-for="user in users | filterBy searchKey | paginate">{{ user.name }}</li>
I would like to replace this with something that Vue 2 will support and will work the same way.
As of Vue version 2, filters can only be used inside text interpolations ({{ }} tags). See the documentation for migrating from Vue version 1.
You can use a computed property to filter the users and use that computed property in the v-for directive instead:
computed: {
filteredUsers: function() {
let key = this.searchKey.toUpperCase();
return this.users.filter((user) => {
return user.name.toUpperCase().indexOf(key) !== -1
})
},
paginatedUsers: function() {
var list = this.filteredUsers;
this.resultCount = list.length
if (this.currentPage >= this.totalPages) {
this.currentPage = this.totalPages
}
var index = this.currentPage * this.itemsPerPage
return list.slice(index - 1, index - 1 + this.itemsPerPage)
}
}
<li v-for="user in paginatedUsers">{{ user.name }}</li>
Also, when using v-for to generate a range of numbers like you do for your page numbers, Vue version to starts the index at 1 instead of 0. So, you'll need to update the logic depending on a starting index of 0 as well.
Here's a working fiddle.

How can I add 2 condition in one class vue.js 2?

My vue component is like this :
<template>
<a :class="'btn ' + [respond == 'responseFound' ? ' btn-yellow' : ' btn-default', type == 1 ? ' btn-block' : ' btn-xs center-block']">
...
</a>
</template>
I try like that, but it does not work?
You can use :class="[array, of, classes]" syntax:
<a :class="['btn', (respond === 'responseFound' ? 'btn-yellow' : 'btn-default'), (type === 1 ? 'btn-block' : 'btn-xs center-block')]">
As a bonus you don't have to worry about adding the leading spaces, Vue will handle it.
Just to keep things clean in view/template/markup, move your conditions to computed properties:
<template>
<a :class="['btn', getRespondClass, getTypeClass]">
</template>
<script>
export default {
data () {
return {
respond: '',
type: ''
}
},
computed: {
getRespondClass () {
return this.respond === 'responseFound' ? 'btn-yellow' : 'btn-default'
},
getTypeClass () {
return this.type === 1 ? 'btn-block' : 'btn-xs center-block'
}
}
}
</script>
Pretty sure the current showed answer says how you can add multiple classes on 1 condition. But if you want to have multiple conditions for your class added you can simply just do it like this:
:class="{'classname': condition_one && condition_two}"
Or you can do this:
:class="[ condition1 | condition2 ? 'className' : '']"
This checks for either of the conditions to be true. If you want to check for both replace | with &&. But if you have nothing in the else class, I think #Marnix's answer is cleaner.

PHPbb Passing parameters or define parameters

How can {CONSTANT} at the aboutus.html can display "Hello world." which i defined at aboutus.php ?
Many Many Thanks.
aboutus.php - I have define CONSTANT to hello world.
<?php
define('IN_PHPBB', true);
$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
include($phpbb_root_path . 'common.' . $phpEx);
define("CONSTANT", "Hello world.");
// Start session management
$user->session_begin();
$auth->acl($user->data);
$user->setup();
if ($user->data['user_id'] == ANONYMOUS)
{
login_box('', $user->lang['LOGIN']);
}
page_header('Title Here');
$template->set_filenames(array(
'body' => 'aboutus_body.html',
));
make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"));
page_footer();
?>
aboutus_body.html - how can {CONSTANT} display "Hello World." that defined above?
<h2>About Us2</h2>
<div class="panel">
<div class="inner"><span class="corners-top"><span></span></span>
<div class="content">
<p>
We were founded this year to bring you the best forum on the Internet!
We promise to do the following:
<ul>
<li>Provide new content</li>
<li>provide a friendly atmosphere</li>
<li>Provide an environment where you can have fun!</li>
</ul>
<p>{CONSTANT}</p>
</p>
</div>
<span class="corners-bottom"><span></span></span></div>
</div>
Template variables, as you are trying to define, are not traditional PHP Constants. Instead, they are assigned to the template from the PHP file using the template class's assign_var()/assign_vars()/assign_block_vars() methods.
For instance:
<?php
// assign a single template variable
$template->assign_var('CONSTANT', 'Hello World');
/// assign an array of template variables
$template->assign_vars(array(
'CONSTANT' => 'Hello World',
'CONSTANT2' => 'Goodbye World',
));
// assign a loop/block
for($i = 0;....)
{
$template->assign_block_vars('blockname', array(
'CONSTANT' => 'Hello World',
));
}
?>
Note that template variables must be UPPERCASE, and block names must be lowercase.
You then call the variable in the file like so: {CONSTANT}
For a block:
<!-- BEGIN blockname -->
{blockname.CONSTANT}
<!-- END blockname -->