Vue js putting id to v-model - javascript

I'm trying to create a question adder for my quiz. Each question has answers, containing IDs:
var questions = [
{
question: "1+1 is",
answers: [
{ id: 0, answer: "1", correct: false },
{ id: 1, answer: "0", correct: false },
{ id: 2, answer: "2", correct: false }
],
correct: [2],
selected: [],
false: [0, 1]
}]
but I don't know how to create an array of objects with IDs. I know that answercorrect, answerfalse1/2 are wrong, but what do I do instead?
Some HTML:
<label>Otázka: <input v-model="question" type="text"></label><br><br>
<label>Správná odpověď: <input v-model="answercorrect" type="text"></label><br><br>
<label>Odpověď: <input v-model="answerfalse" type="text"></label><br><br>
<label>Odpověď: <input v-model="answerfalse2" type="text"></label>
JS:
addQuestion()
{
if (this.question != "")
{
this.questions.push(this.question);
this.question = "";
this.questions.push(this.answers[this.answercorrect, this.answerfalse, this.answerfalse2]);
this.answercorrect = "";
this.answerfalse = "";
this.answerfalse2 = "";
}
}

I would create a function that generates a blank question object, containing an array of generated answer objects.
let answerId = 0;
let questionId = 0;
const createAnswer = () => ({ id: answerId++, answer: '', correct: false })
const createQuestion = () => ({
id: questionId++,
question: '',
answers: [createAnswer()],
})
A component would use those functions to add new questions and answers:
export default {
data() {
return {
questions: [createQuestion()],
};
},
methods: {
addQuestion() {
this.questions.push(createQuestion())
},
addAnswer(q) {
/**
* Since the `answers` object is part of the `questions` object,
* this takes a question as an argument, and adds a new `answer`
* object to its `answers` array.
*/
q.answers.push(createAnswer())
},
},
}
In the template, use v-for to render the questions, and use v-on button-click handlers that bind to the component's addQuestion() and addAnswer():
<template>
<div>
<button #click="addQuestion">Add question</button>
<fieldset class="question" v-for="q in questions" :key="q.id">
<legend>Question: <input v-model="q.question" type="text" /></legend>
<button #click="addAnswer(q)">Add answer</button>
<label class="answer" v-for="answer in q.answers" :key="answer.id">
Answer: <input type="text" v-model="answer.answer" />
Correct: <input type="checkbox" v-model="answer.correct" />
</label>
</fieldset>
</div>
</template>
demo

Related

edgesData.forEach is not a function in Angular

import { Component, AfterViewInit, ElementRef, ViewChild } from '#angular/core';
import { Network, DataSet, DataView} from 'vis';
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent implements AfterViewInit {
#ViewChild('network', {static: false}) el: ElementRef;
#ViewChild('nodeFilterSelect', {static:false}) nodeFilter: ElementRef;
#ViewChild('edgesFilter', {static: false}) edgeFilter: ElementRef;
private networkInstance: any;
startNetwork(data){
const container = this.el.nativeElement;
this.networkInstance = new Network(container, data, {});
}
ngAfterViewInit() {
const nodes = new DataSet<any>([
{ id: 1, label: 'Eric Cartman', age: 'kid', gender: 'male' },
{ id: 2, label: 'Stan Marsh', age: 'kid', gender: 'male' },
{ id: 3, label: 'Wendy Testaburger', age: 'kid', gender: 'female' },
{ id: 4, label: 'Mr Mackey', age: 'adult', gender: 'male' },
{ id: 5, label: 'Sharon Marsh', age: 'adult', gender: 'female' }
]);
const edges = new DataSet<any>([
{ from: 1, to: 2, relation: 'friend', arrows: 'to, from', color: { color: 'red'} },
{ from: 1, to: 3, relation: 'friend', arrows: 'to, from', color: { color: 'red'} },
{ from: 2, to: 3, relation: 'friend', arrows: 'to, from', color: { color: 'red'} },
{ from: 5, to: 2, relation: 'parent', arrows: 'to', color: { color: 'green'} },
{ from: 4, to: 1, relation: 'teacher', arrows: 'to', color: { color: 'blue'} },
{ from: 4, to: 2, relation: 'teacher', arrows: 'to', color: { color: 'blue'} },
{ from: 4, to: 3, relation: 'teacher', arrows: 'to', color: { color: 'blue'} },
]);
/**
* filter values are updated in the outer scope.
* in order to apply filters to new values, DataView.refresh() should be called
*/
let nodeFilterValue = ''
const edgesFilterValues = {
friend: true,
teacher: true,
parent: true
}
/*
filter function should return true or false
based on whether item in DataView satisfies a given condition.
*/
const nodesFilter = (node) => {
if (nodeFilterValue === '') {
return true
}
switch(nodeFilterValue) {
case('kid'):
return node.age === 'kid'
case('adult'):
return node.age === 'adult'
case('male'):
return node.gender === 'male'
case('female'):
return node.gender === 'female'
default:
return true
}
}
const edgesFilter = (edge) => {
return edgesFilterValues[edge.relation]
}
const nodesView = new DataView(nodes, {filter: nodesFilter})
const edgesView = new DataView(edges, {filter: nodesFilter})
this.nodeFilter.nativeElement.addEventListener('change', (e) => {
// set new value to filter variable
nodeFilterValue = e.target.value
/*
refresh DataView,
so that its filter function is re-calculated with the new variable
*/
nodesView.refresh()
})
const selectors = this.edgeFilter.nativeElement.querySelectorAll('label')
console.log(selectors)
selectors.forEach(filter => filter.addEventListener('change', (e) => {
const { value, checked } = e.target
edgesFilterValues[value] = checked
edgesView.refresh()
}))
this.startNetwork({ nodes: nodesView, edges: edgesView })
}
}
For codes above I encountered a error saying edgesData.forEach is not a function in Angular. I think this error came from this code snippet:
const selectors = this.edgeFilter.nativeElement.querySelectorAll('label')
console.log(selectors)
selectors.forEach(filter => filter.addEventListener('change', (e) => {
const { value, checked } = e.target
edgesFilterValues[value] = checked
edgesView.refresh()
}))
Actually what I want to do is to add event listener to my three input values. the html like:
<div>
<label>
Filter nodes
<select #nodeFilterSelect>
<option value=''>All characters</option>
<option value='kid'>kids</option>
<option value='adult'>adults</option>
<option value='male'>male</option>
<option value='female'>female</option>
</select>
</label>
<br>
<br>
<label #edgesFilter>
Filter edges
<div>
<label>
<input type='checkbox' value='parent' checked>
Is <span style="color:green">parent</span> of
</label>
</div>
<div>
<label>
<input type='checkbox' value='teacher' checked>
Is <span style="color:blue">teacher</span> of
</label>
</div>
<div>
<label>
<input type='checkbox' value='friend' checked>
Is <span style="color:red">friend</span> of
</label>
</div>
</label>
</div>
<div #network>
</div>
what happened here, can any body explain for a little bit? I think I used 'foreach' in a wrong way, I googled a lot, but still confused about how to loop through and add the listeners.
Also I tried to use for loop instead of foreach:
const selectors = this.edgeFilter.nativeElement.querySelectorAll('input')
for(const selector of selectors){
console.log(selector)
selector.forEach(filter => filter.addEventListener('change', (e) => {
const { value, checked } = e.target
edgesFilterValues[value] = checked
edgesView.refresh()
}))
}
Still got error saying :
ERROR TypeError: selector.forEach is not a function
at TestComponent.ngAfterViewInit (main.js:294)
at callProviderLifecycles (vendor.js:64080)
at callElementProvidersLifecycles (vendor.js:64045)
at callLifecycleHooksChildrenFirst (vendor.js:64027)
at checkAndUpdateView (vendor.js:74910)
at callViewAction (vendor.js:75266)
at execComponentViewsAction (vendor.js:75194)
at checkAndUpdateView (vendor.js:74907)
at callWithDebugContext (vendor.js:76241)
at Object.debugCheckAndUpdateView [as checkAndUpdateView] (vendor.js:75823)
I just realize this is a problem of visjs, i need to install #type/vis
You are actually adding the event to label elements, that is not going to work. The change event works on input, select or textarea.
I would say that it doesn't look the Angular way to me, but maybe I am not seeing the whole picture. I would do something like this, it is just the part of the controls and events,
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
filterNodes = '';
selectChange () {
console.log(`filterNodes: ${this.filterNodes}`);
}
chkChange(evt) {
const { value, checked } = evt.target;
console.log(`${value}: ${checked}`);
}
}
<div>
<label>
Filter nodes
<select [(ngModel)]="filterNodes"
(change)="selectChange()">
<option value=''>All characters</option>
<option value='kid'>kids</option>
<option value='adult'>adults</option>
<option value='male'>male</option>
<option value='female'>female</option>
</select>
</label>
<br>
<br>
<label>
Filter edges
<div>
<label>
<input type='checkbox' value='parent' checked
(change)="chkChange($event)">
Is <span style="color:green">parent</span> of
</label>
</div>
<div>
<label>
<input type='checkbox' value='teacher' checked
(change)="chkChange($event)">
Is <span style="color:blue">teacher</span> of
</label>
</div>
<div>
<label>
<input type='checkbox' value='friend' checked
(change)="chkChange($event)">
Is <span style="color:red">friend</span> of
</label>
</div>
</label>
</div>
this.edgeFilter.nativeElement.querySelectorAll('label')
above given line will return, the type NodeList[], So you can convert NodeList[] into the array by
this.edgeFilter.nativeElement.querySelectorAll('label')
Try this, code snippet
const selectors = [].slice.call(this.edgeFilter.nativeElement.querySelectorAll('label'), 0);
console.log(selectors)
selectors.forEach(filter => filter.addEventListener('change', (e) => {
const { value, checked } = e.target
edgesFilterValues[value] = checked
edgesView.refresh()
}))
querySelecterAll returns a NodeList. So instead of for(const selector of selectors){ you can directly iterate on selectors with selectors.forEach. So, that part should be:
const selectors = this.edgeFilter.nativeElement.querySelectorAll('input')
selectors.forEach(filter => filter.addEventListener('change', (e) => {
const { value, checked } = e.target;
edgesFilterValues[value] = checked;
edgesView.refresh();
}))

Having trouble sorting ul list items alphabetically (ascending/descending) in React.js

I am brand new to React so it is possible that this is a really dumb question, but I could really use some help! I've looked all over and I can't figure out why the sortList function does nothing. Here is the beginning of my component code:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [
{
id: 1,
text: 'bananas',
done: false
},
{
id: 2,
text: 'milk',
done: false
},
{
id: 3,
text: 'bread',
done: false
},
{
id: 4,
text: 'cheese',
done: false
}
],
text: "",
ascending: true
};
this.handleNewText = this.handleNewText.bind(this);
this.addItem = this.addItem.bind(this);
this.handleCheckOff = this.handleCheckOff.bind(this);
this.handleDeleteItem = this.handleDeleteItem.bind(this);
this.sortList = this.sortList.bind(this);
}
and the function that won't work...
sortList() {
let newList = this.state.items.sort((a,b) => {
if (this.state.ascending) {
return a.text - b.text;
} else {
return b.text - a.text;
}
});
this.setState({
ascending: !this.state.ascending,
items: newList
});
}
and the render function...
render() {
return (
<div className="col-lg-6">
<form>
<input type="text" id="textBox" className="form-control" onChange={this.handleNewText} value={this.state.text} />
<button id="addButton" className="btn btn-primary" onClick={this.addItem} disabled={!this.state.text}>{"Add Item"}</button>
</form>
<div id="postIt">
<h1>Shopping List</h1>
<List items={this.state.items} onItemCheckedOff={this.handleCheckOff} onDeleteItem={this.handleDeleteItem} />
<button id="sortButton" className="btn btn-primary" onClick={this.sortList}>{"Sort"}</button>
</div>
</div>
);
}
}
Everything is working great except for the SortList function. I've tried a number of different approaches and can't get it to work. The most that happened was the list items disappeared!
You where trying to subtract 2 strings from each other which returns Nan. Sort wants 1 or -1
let newList = this.state.items.sort((a, b) => {
if (this.state.ascending && a.text > b.text) {
return 1;
} else {
return -1;
}
});
hope that answers your question

Add and remove objects from array using checkboxes

I have implemented check-boxes on a screen in react native and what I am trying to achieve is that upon selection of checkbox it would add that object to an array and upon unchecking it would remove it from the array.
I have tried using filter method as well as loops but it doesn't work the way it is required.
for (let i = 0; i<tmp.length; i++){
console.log("length",tmp.length)
if(tmp.id == item.id){
tmp.splice(tmp.indexOf(item.id),1);
// tmp.pop(item)
console.log("POP")
}
else {
tmp.push(item);
console.log("PUSH")
}
}
My array of objects is as follows:
contacts:[
{name:'a', id:1, plant:3},
{name:'b', id:2, plant:1},
{name:'c', id:3, plant:1}
],
Code for checkboxes:
<CheckBox
checked={this.state.selectedCheckList.includes(item.id)? true:false}
onPress={()=>this.onCheckboxPress(item)} color={"#8BC63E"}
/>
I expect the array that I am creating in tmp to be dynamic, in such a way that it removes and adds whole specific objects from the array.
Before:
tmp:[
{name:'a', id:1, plant:3},
{name:'b', id:2, plant:1},
{name:'c', id:3, plant:1}
],
After:
tmp:[
{name:'a', id:1, plant:3},
{name:'c', id:3, plant:1}
],
Although this question is React Native related, all the answers are HTML+JS.
The solution is to create a new array out of existing one and append it to the state:
onCheckboxPress = (item) => {
const selectedCheckList = contacts.filter((contact) => contact.id !== item.id);
this.setState({ selectedCheckList });
}
And then in the component, you check the state with:
<CheckBox
checked={() => this.isInList(item)}
onPress={()=>this.onCheckboxPress(item)} color={"#8BC63E"}
/>
where the function looks like:
isInList = (item) => {
const { selectedCheckList } = this.state;
return selectedCheckList.some((listItem) => listItem.id === item.id);
}
Hope this helps you on.
Try this::
var arr=[];
function change(checkbox)
{
if(checkbox.checked == true)
{
arr.push(checkbox.value);
}
else
{
var j = arr.indexOf(checkbox.value);
arr.splice(j, 1);
}
var stringArr=arr.join(',');
document.getElementById('display').innerHTML=stringArr;
}
<div>
<label>
<input type="checkbox" name="check" value="Check 1" onchange="change(this)">A</label>
<label>
<input type="checkbox" name="check" value="Check 2" onchange="change(this)">B</label>
<label>
<input type="checkbox" name="check" value="Check 3" onchange="change(this)">C</label>
<label>
<input type="checkbox" name="check" value="Check 4" onchange="change(this)">D</label>
</div>
<div id="display">
</div>

ReactJs: How can I show the correct questionnaire answer and the total score?

I am new to react and I want to arrange the correct option of each question on the same page. Also, when the question is solved it should show whether it is correct or not. In the end, I need the total score. How can I accomplish that? Thank you for the help in advance.
This what I have done so far..( Normally there are more questions but I had to delete them to post)
const questionsArray = [
{
question: 'When the C programming language has first appeared?',
option1: '1970',
option2: '1971',
option3: '1972'
},
{
question: 'When the Java programming language has first appeared?',
option1: '1994',
option2: '1995',
option3: '1996'
},
];
class QuizAppQuestion extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
currentQuestionIndex: 0,
questions: [],
answers: []
};
}
componentDidMount() {
this.setState({questions: questionsArray})
}
onChangeOption(value) {
const {currentQuestionIndex} = this.state;
let answers = {...this.state.answers};
answers[currentQuestionIndex] = value;
this.setState({answers});
}
handleNext() {
let incrementCurrentQuestionIndex = this.state.currentQuestionIndex + 1;
this.setState({currentQuestionIndex: incrementCurrentQuestionIndex});
}
render() {
const {questions, currentQuestionIndex, answers} = this.state;
if (!questions.length) {
return <div>Loading questions...</div>
}
if (currentQuestionIndex >= questions.length) {
return (<div><h3>End of the quiz</h3></div>)
}
const {question, option1, option2, option3} = questions[currentQuestionIndex];
return (<div>
<h1>Question {currentQuestionIndex + 1}</h1>
<h4>{question}</h4>
<label>
<input type='radio' checked={answers[currentQuestionIndex] === option1} value={option1} onChange={(evt) => this.onChangeOption(evt.target.value)}/>
{option1}
</label>
<br/>
<label>
<input type='radio' checked={answers[currentQuestionIndex] === option2} value={option2} onChange={(evt) => this.onChangeOption(evt.target.value)}/>
{option2}
</label>
<br/>
<label>
<input type='radio' checked={answers[currentQuestionIndex] === option3} value={option3} onChange={(evt) => this.onChangeOption(evt.target.value)}/>
{option3}
</label>
<hr/>
<button onClick={() => this.handleNext()}>Next</button>
</div>);
}
}
You would want to make a separate array that holds the answers, and test the selected answer against the appropriate question/answer in your answers array. So in your case something like:
const answerArray = [
{
question: "When the C programming language has first appeared?",
answer: "option1"
}
]
onSubmit = (selectedAnswer) => { // Selected answer is the option picked from your select menu
if(selectedAnswer === answerArray[currentQuestionIndex].answer) {
// Logic for correct answer
} else {
// Logic for incorrect answer
}
}

How can I create an object that I can concat onto an array in React?

This is the array I would like to concat to
venues: [
{
name: "Picnic",
rating: 5
},
{
name: "Mr Tulk",
rating: 4
},
{
name: "Auction Rooms",
rating: 3,
}
]
This is the code for my class where I am getting the value from the input.
I have set the key to the variable holding the values of the input but am getting a syntax error.
class AddVenue extends React.Component {
onFormSubmit = (e) => {
e.preventDefault();
const venueName = e.target.elements.name.value;
const rating = e.target.elements.rating.value;
if (venueName && rating) {
{
name: venueName,
rating: rating
}
}
}
render() {
return (
<form onSubmit={this.onFormSubmit}>
<input type="text" name="name" />
<input type="text" rating="rating" />
<button>Add Venue</button>
</form>
)
}
}
Also I figure I don't need to assign it to a variable or create a new instance as each object in my array isn't assigned to a variable?
I don't want to use a JSON object yet as I want to keep it really basic for now as I'm learning and playing with React and JavaScript
Could you also please explain why this doesn't work and why your answer works please :-)
Instead of
if (venueName && rating) {
{
name: venueName,
rating: rating
}
Change it to
if (venueName && rating) {
venues.push({
name: venueName,
rating: rating
});
}
venues is an array and hence in order to add new element into it, you can use push method

Categories

Resources