If I have the array:
let messages = [
{
username: 'john',
message: 'hi'
},
{
username: 'john',
message: 'there'
},
{
username: 'bob',
message: 'hello'
},
{
username: 'john',
message: 'whats up'
}
]
If i have messages like:
In vuejs rendered out how would I combine messages with the same username and render the text under each other?
Don't to it in the view, use a computed to get the data you want. You can then use <template> tags to control which elements are shown, that way you don't need to wrap the elements into a single DOM element.
Below is an example that shows a straight forward way of generating an array for the computed that can then be iterated over.
Vue.createApp({
data() {
return {
messages: [{
username: 'john',
message: 'hi'
},
{
username: 'john',
message: 'there'
},
{
username: 'bob',
message: 'hello'
},
{
username: 'john',
message: 'whats up'
}
]
}
},
computed: {
byUser() {
const arr = [];
let tempName = null;
let tempGroup = {}
this.messages.forEach(m => {
if (tempName !== m.username) {
tempGroup = {
username: m.username,
messages: []
}
arr.push(tempGroup);
}
tempGroup.messages.push(m.message);
tempName = m.username;
})
return arr;
}
}
}).mount("#app")
<script src="https://unpkg.com/vue#next/dist/vue.global.prod.js"></script>
<div id="app" class="container">
<template v-for="(m, i) in byUser">
<h2>
{{ m.username }}
</h2>
<p v-for="message in m.messages">
{{ message }}
</p>
<hr>
</template>
</div>
Related
In a Vue3/InertiaJS project, I am attempting to do a simple dynamic select list population, but I'm having issues reading the props data to populate the dropdown.
<script setup>
import {Head, Link, useForm} from '#inertiajs/inertia-vue3'
import SelectInput from '#/Components/ping/SelectInput.vue'
import {ref} from 'vue';
const props = defineProps({
areas: [
{
id:1,
name:"Club",
approvers: [
{
id:12,
first_name: "Joe",
last_name: "Blow"
}
]
},
{
id:2,
name:"Adult Small Bore",
approvers: [
{
id:34,
first_name: "Sam",
last_name: "Snead"
}
]
},
{
id:3,
name:"Appleseed",
approvers: [
{
id:56,
first_name: "Johhny",
last_name: "Appleseed"
}
]
},
{
id:4,
name:"Archery",
approvers: [
{
id:56,
first_name: "Jim",
last_name: "Beam"
},
{
id:56,
first_name: "Jack",
last_name: "Daniels"
}
]
},
{
id:5,
name:"Armed Women of America",
approvers: [
{
id: 99,
first_name: "Amelia",
last_name: "Earhart"
}
]
}
]
})
const form = useForm({
date: '',
hours: '',
area: '',
reason: '',
comments: '',
approver: ''
});
let selectApprovers = ref([]);
function updateApprovers(event) {
const area = props.areas.filter(area => area.id === parseInt(event.target.value));
console.log({area});
selectApprovers.value = area.approvers.map(function (item) {
return {
id: item.id,
name: item.first_name + ' ' + item.last_name
}
});
selectApprovers.value = approvers;
}
function store() {
form.post(`/admin/work-hours`)
}
</script>
<template>
<div>
<form #submit.prevent="store">
<select-input v-model="form.area" :error="form.errors.area"
class="pb-8 pr-6 w-full lg:w-1/2" label="Area" #change="updateApprovers">
<option :value="null" />
<option v-for="area in props.areas" :key="area.id" :value="area.id">{{ area.name }}</option>
</select-input>
<select-input v-model="form.approver" :error="form.errors.approver"
class="pb-8 pr-6 w-full lg:w-1/2" label="Approver">
<option :value="null" />
<option v-for="approver in selectApprovers" :key="approver.id" :value="approver.id">{{ approver.name }}</option>
</select-input>
</form>
</div>
</template>
where the <select-list> input is just a wrapper around a standard <select> element.
The props in the real app are coming from Laravel via InertiaJS. The issue I am having is in updateApprovers(). This line works fine:
const area = props.areas.filter(area => area.id === parseInt(event.target.value));
as seen in the console.log({area}). However, it errors out at the next line when it tries to read area.approvers, and I get the error
Uncaught TypeError: can't access property "map", area.approvers is undefined
I've tried using value
selectApprovers.value = area.value.approvers.map(function (item) {
but I get the same error. Visual inspection of the props in Vue dev tools shows that the approvers array is there; what do I need to change to be able to access it?
I've tried setting up an sfc playground, but for some reason it's having issues reading the v-for loop.
Array.filter always returns another array, so this line:
const area = props.areas.filter(area => area.id === parseInt(event.target.value));
results in area being an array of objects. Those individual objects may each have an inner approvers array, but the area array itself has no approvers property, which is why area.approvers.map() throws an error.
You could do area[0].approvers.map(), but I think a more appropriate Array function to use in the first place would be Array.find to return the first matching object which you could then map.
function updateApprovers(event) {
const area = props.value.areas.find(
area => area.id === parseInt(event.target.value)
);
selectApprovers.value = area.approvers.map(function (item) {
return {
id: item.id,
name: item.first_name + ' ' + item.last_name
};
});
}
I'm trying to validate a string with Yup:
const schema = object({
firstname: string().optional().nullable().notRequired().min(2),
});
The rules should be a string but can be null or empty, and if there is a value, then the length must be more than 2.
But for some reason, it's not working:
const shouldWorks = [
{ firstname: 'bla' },
{ firstname: '' }, <--- its failed here.. empty is okay (.notRequired)
{ firstname: null },
];
How do I change the schema to fit my rules?
stackblitz
import { object, string } from 'yup';
console.clear();
const shouldWorks = [
{ firstname: 'bla' },
{ firstname: '' },
{ firstname: null },
];
const shouldNotWork = [{ firstname: 'a' }];
const schema = object({
firstname: string().optional().nullable().notRequired().min(2),
});
shouldWorks.forEach((obj, i) => {
console.log(`test: ${i}`);
schema.validateSync(obj);
});
shouldNotWork.forEach((obj, i) => {
try {
schema.validateSync(obj);
console.log(`error test: ${i} failed`);
} catch (e) {
console.log(`error test: ${i} pass`);
}
});
You can use yup.lazy to lazily decide what validators to use based on the value:
const schema = object({
firstname: lazy((value) =>
value === ''
? string()
: string().optional().nullable().notRequired().min(2)
),
});
Stackblitz
I have an object with users:
const data = [
{
name: "John",
lastName: "Doe",
email: "stefa#gmail.com",
password: "123",
following: [{ id: "113"}, { id: "111" } }],
id: "112",
},
{
name: "Jane",
lastName: "Doe",
email: "dusica#gmail.com",
password: "123",
following: [{ id: "112" }],
id: "113",
},
{
name: "Mark",
lastName: "Twain",
email: "marko#gmail.com",
password: "123",
following: [],
id: "111",
},
];
As you can see all users have an array named "following", and that array contains id's of users which the user follows. I want to access that array "following" to find out which users are not followed. Let's say that we want to check the "following" array of the first user John Doe with id="112".
const followers = [];
let suggestions = null;
props.users.forEach((user) => {
if (user.id === '112') {
user.following.forEach((item) => {
followers.push(item);
});
}
});
followers.map((item) => {
suggestions = props.users.map((user) => {
if (user.id !== item.id && user.id !== '112) {
console.log(item.id);
return <div>something</div>;
}
});
});
I tried something like this, but the result is not what i expected to be. As i said, i want to return users that are not followed and render them because i want them to be visible so the user can follow them. I hope that i was understandable enough. Thanks.
It's a negative comparison.
So you want to filter out all users that a user IS following.
You can loop through each user and compare it against the following array. If the following array contains the user then don't show it.
const notFollowing = allUsers.filter(user =>
!currentUser.following.some(({ id }) => id === user.id)
);
I want to search by header and content. for now can only be based on content. any suggestions or can add from this source code. Thank you
Here is my HTML
<div id="list">
<input type="text" v-model="search">
<ol>
<li v-for="(items, key) in groupedItems">
<h3>{{ key }}</h3>
<p v-for="todo in items">{{ todo.name }}</p>
</li>
</ol>
</div>
here is preview code in js fiddle: https://jsfiddle.net/60jtkp30/9/
It may not be the cleanest solution, but based on your implementation in the jdfiddle, just changing the filter function would be enough (I think).
var list = new Vue({
el: '#list',
data: {
search: '',
items: [
{ name: 'mike', type: 'student' },
{ name: 'beckham john', type: 'footballer' },
{ name: 'walcott', type: 'footballer' },
{ name: 'cech', type: 'footballer' },
{ name: 'jordan', type: 'actor' },
{ name: 'tom', type: 'actor' },
{ name: 'john', type: 'actor' }
]
},
computed: {
groupedItems() {
const arr = {}
//fungsi search
var searchResult = this.items.filter( todo => {
return todo.name.toLowerCase().indexOf(this.search.toLowerCase())>-1 || todo.type.toLowerCase().indexOf(this.search.toLowerCase())>-1;
} )
//grouping
for(var i = 0; i < searchResult.length; i++) {
const key = searchResult[i].type
if (arr[key]) {
arr[key].push(searchResult[i])
} else {
arr[key] = [searchResult[i]]
}
}
return arr
}
}
})
In PHP you could say SELECT "message" FROM "users" WHERE id = $id But how do can I select in AngularJS (JavaScript) like the PHP way.
Here are my services at the moment:
app.service("users", function() {
this.userList = [
{
userId: 1,
username: "John",
password: "Doe"
},
{
userId: 2,
username: "Jane",
password: "Doe"
}
];
this.text = function() {
return "Hello";
};
});
app.service("userMessages", function() {
this.messages = [
{
userId: 1,
message: [
{
text: "This is a message from user 1"
},
{
text: "This is another message from user 1"
}
]
},
{
userId: 2,
message: [
{
text: "This is a message from user 2"
},
{
text: "This is another message from user 2"
}
]
}
]
});
And my controller is like this:
app.controller("controller", function($scope, users, userMessages) {
$scope.users = users.userList;
var id = $scope.users.length
$scope.add = function() {
$scope.users.push(
{
userId: ++id,
username: $scope.username,
password: $scope.password
}
);
$scope.username = "";
$scope.password = "";
};
});
And here is the HTML:
<div class="container" ng-controller="controller">
<div ng-repeat="user in users">
{{ user.userId }}<br />
{{ user.username }}<br />
{{ user.password }}<br />
<hr />
</div>
<input type="text" ng-model="username" placeholder="Username"><br />
<input type="text" ng-model="password" placeholder="Password"><br />
<button ng-click="add()">Add user</button>
</div>
This is a simple test that I made to see how I could display the messages from the userMessages service and link them to the users in the users service.
I have no idea how to do this.
I have done some research but I could not find a solution. Any help would be appreciated.
You can use ng-if to compare the users.userId and messages.userId and display them according to the user
Here is the working plunker
http://embed.plnkr.co/39Dd6AtKorcxX24fNmJF/preview
Hope this helps!!!!
Here's some data to show you how you can use javascripts Array.prototype.filter to grab data from arrays based on a parameter.
angular.module('app', [])
.service('users', function() {
this.userList = [{
userId: 1,
username: "John",
password: "Doe"
}, {
userId: 2,
username: "Jane",
password: "Doe"
}];
this.text = function() {
return "Hello";
};
})
.service('userMessages', function() {
var messages = [{
userId: 1,
messages: [{
text: "This is a message from user 1"
}, {
text: "This is another message from user 1"
}]
}, {
userId: 2,
messages: [{
text: "This is a message from user 2"
}, {
text: "This is another message from user 2"
}]
}];
this.getUsersMessages = function(id) {
return messages.filter(function(obj, i) {
return obj.userId == id;
});
}
})
.controller('testCtrl', ['$scope', 'users', 'userMessages',
function($scope, users, userMessages) {
$scope.user1 = users.userList[0];
$scope.user2 = users.userList[1];
$scope.user1Messages = userMessages.getUsersMessages($scope.user1.userId);
$scope.user2Messages = userMessages.getUsersMessages($scope.user2.userId);
}
]);
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.css" rel="stylesheet" />
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body ng-app="app">
<div ng-controller="testCtrl">
{{user1Messages}}
<br />
{{user2Messages}}
</div>
</body>
</html>
SELECT * FROM * WHERE has nothing to do with PHP, it's SQL language of a database, like MySQL.
When you want to make queries to javascript array consider using methods of javascript array.