I'm working on a quiz app that is based on a 'string' answered instead of the variable 'number'. I tried different syntax but it just displays a blank with no data/error displayed. As you can see my code below, I'll give you an example logic that I want.
if(answer.correct == "answerstring"){displayvariable == "STRINGTOBEDISPLAYED"};
Here is my 'question.json'
{
"questions": [
{
"flashCardFront": "<img src='assets/questionimg/12_plate1.gif' />",
"flashCardBack": "12",
"flashCardFlipped": false,
"questionText": "What number is this?",
"answers": [
{"answer": "12", "correct": true, "selected": false},
{"answer": "17", "correct": false, "selected": false},
{"answer": "NOTHING", "correct": false, "selected": false}
]
},
{
"flashCardFront": "<img src='assets/questionimg/8_plate2.gif' />",
"flashCardBack": "8",
"flashCardFlipped": false,
"questionText": "What is number is this?",
"answers": [
{"answer": "3", "correct": false, "selected": false},
{"answer": "8", "correct": true, "selected": false},
{"answer": "NOTHING", "correct": false, "selected": false}
]
},
{
"flashCardFront": "<img src='assets/questionimg/29_plate3.gif' />",
"flashCardBack": "29",
"flashCardFlipped": false,
"questionText": "What is this?",
"answers": [
{"answer": "70", "correct": false, "selected": false},
{"answer": "NOTHING", "correct": false, "selected": false},
{"answer": "29", "correct": true, "selected": false}
]
}
]
}
My data.ts where my dataprovider is located.
import { Injectable } from '#angular/core';
import 'rxjs/add/operator/map';
import { HttpClient } from '#angular/common/http';
/*
Generated class for the DataProvider provider.
See https://angular.io/guide/dependency-injection for more info on providers
and Angular DI.
*/
#Injectable()
export class DataProvider {
data: any;
constructor(public http: HttpClient) {
}
load(){
if(this.data){
return Promise.resolve(this.data);
}
return new Promise(resolve => {
this.http.get('assets/data/questions.json').subscribe((data:any) => {
this.data = data.questions;
resolve(this.data);
});
});
}
}
My typescript where the quiz is being processed
import { Component, ViewChild} from '#angular/core';
import { NavController} from 'ionic-angular';
import { DataProvider } from '../../providers/data/data';
/**
* Generated class for the IshiharaQuestionsPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#Component({
selector: 'page-ishihara-questions',
templateUrl: 'ishihara-questions.html',
})
export class IshiharaQuestionsPage {
#ViewChild('slides') slides: any;
hasAnswered: boolean = false;
score: number = 0;
cvd: string;
slideOptions: any;
questions: any;
constructor(public navCtrl: NavController, public dataService: DataProvider) {
}
ionViewDidLoad() {
this.slides.lockSwipes(true);
this.dataService.load().then((data) => {
data.map((question) => {
let originalOrder = question.answers;
question.answers = this.randomizeAnswers(originalOrder);
return question;
});
this.questions = data;
});
}
nextSlide(){
this.slides.lockSwipes(false);
this.slides.slideNext();
this.slides.lockSwipes(true);
}
selectAnswer(answer, question){
this.hasAnswered = true;
answer.selected = true;
question.flashCardFlipped = true;
if(answer.correct){
this.score++;
}
setTimeout(() => {
this.hasAnswered = false;
this.nextSlide();
answer.selected = false;
question.flashCardFlipped = false;
}, 3000);
}
randomizeAnswers(rawAnswers: any[]): any[] {
for (let i = rawAnswers.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
let temp = rawAnswers[i];
rawAnswers[i] = rawAnswers[j];
rawAnswers[j] = temp;
}
return rawAnswers;
}
restartQuiz() {
this.score = 0;
this.slides.lockSwipes(false);
this.slides.slideTo(1, 1000);
this.slides.lockSwipes(true);
}
}
and this is where I want to display that string.
<ion-slide>
<ion-card>
<h2 text-justify padding>The 24 plate quiz suggests that you might currenly belong to this CVD type:</h2>
<br>
<br>
<br>
<h1 color="danger">{{cvd}}</h1> <<-----------------THIS LINE
<br>
<br>
<br>
<h2>Final Score: {{score}}/24</h2>
<button (click)="restartQuiz()" ion-button full color="primary">Start Again</button>
</ion-card>
</ion-slide>
Ionic syntax are basically uses TypeScript or more specifically similar to Angular (JS/2+) code, in Angular(JS/2+) for string comparison or to check equality we use '===' (triple equal to) rather '=='. Please replace '==' with '===', and it should be working OK.
Related
I have an object with a triple nested objects. I want to flatten the object to clearly review the values and place in an HTML.
{
"templateName": "Test template",
"assignmentGroup": "Test template",
"fields": [{
"type": "Multi Select dropdown",
"entry": [{
"checked": false,
"value": "govtBusinses",
"displayValue": "Government Business Division"
}, {
"checked": true,
"value": "privateSector",
"displayValue": "Private Sector"
}, {
"checked": true,
"value": "publicSector",
"displayValue": "Public Sector"
}]
}, {
"type": "Text Field",
"entry": null
}]
}
I tried flatting it, but I want it to be in desired format.
flattenObject = function(ob) {
let toReturn = {};
for (let i in ob) {
if (!ob.hasOwnProperty(i)) {
continue;
}
if ((typeof ob[i]) === "object") {
let flatObject = this.flattenObject(ob[i]);
for (let x in flatObject) {
if (!flatObject.hasOwnProperty(x)) {
continue;
}
toReturn[i + "." + x] = flatObject[x];
}
} else {
toReturn[i] = ob[i];
}
}
console.log(toReturn);
return toReturn;
};
Expected:
TemplateName : "Test template"
Assignment Group : "sample"
Field 0 :
Type : Multiselect dropdown
Entry 0 :
checked : false
value :
buisness:
Entry 1:
checked : false
value :
buisness:
Field 1:
Type:
.......
How can i achieve this?
You can't have different values with same Key in object. I guess better way to achieve this would be to return array of objects instead.
try this:
let obj = {
"templateName": "Test template",
"assignmentGroup": "Test template",
"fields": [{
"type": "Multi Select dropdown",
"entry": [{
"checked": false,
"value": "govtBusinses",
"displayValue": "Government Business Division"
}, {
"checked": true,
"value": "privateSector",
"displayValue": "Private Sector"
}, {
"checked": true,
"value": "publicSector",
"displayValue": "Public Sector"
}]
}, {
"type": "Text Field",
"entry": null
}]
}
let fieldsCount = []
flattenObject = function(ob, toReturnArr) {
for (let i in ob) {
if (!ob.hasOwnProperty(i)) {
continue;
}
if ((typeof ob[i]) === "object") {
if (isNaN(i)) {
fieldsCount[i] = fieldsCount[i] === undefined ? 0 : fieldsCount[i] + 1
ob[i] && ob[i].length ? console.log(`${i}: ${fieldsCount[i]}`) : null;
}
toReturnArr = this.flattenObject(ob[i], toReturnArr);
} else {
console.log(`${i}: ${ob[i]}`);
toReturnArr.push({
[i]: ob[i]
})
}
}
return toReturnArr;
};
flattenObject(obj, [])
Result:
templateName: Test template
assignmentGroup: Test template
fields: 0
type: Multi Select dropdown
entry: 0
checked: false
value: govtBusinses
displayValue: Government Business Division
checked: true
value: privateSector
displayValue: Private Sector
checked: true
value: publicSector
displayValue: Public Sector
type: Text Field
PS: {[key]: object[key]} using variable for key value like [key] is the ES6 feature.
I have a class and a json object I want the the items in the json object to update the new class. Using Angular 9
class
export class Searchdata{
name:boolean=false;
age:boolean=false;
summer:boolean=false;
winter:boolean=false;
football:boolean=false;
tennis:boolean=false;
}
and the json
[
{
"name": "name",
"visible": true,
},
{
"name": "age",
"visible": true
}, {
"name": "football",
"visible": true
}
]
Json does not always have the same number of elements as the class has properties but if solves it easier it can have all the same number of items. I have tried a number of solutions so for illustrative purposes I below is how I envisaged it working.
permPageData:any="The JsonObject";
tableSearchModel:Searchdata;
someFunction(){
this.tableSearchModel = new Searchdata();
permPageData.forEach(element => {
if(element.name == this.tableSearchModel["element.name"])
this.tableSearchModel[element.name] = element.visible;
}
return this.tableSearchModel;
}
I think if you are going to use a class to represent your model SearchData, then it should be a method of the SearchData.
Something like this,
.ts
class Searchdata{
name = false;
age = false;
summer = false;
winter = false;
football = false;
tennis = false;
constructor() {}
setFromJSON(obj: Array<{name:string,visible:boolean}>) {
obj.forEach(element => {
this[element.name] = element.visible;
});
}
toString() {
return `{name:${this.name},age:${this.age},summer:${this.summer},winter:${this.winter},football:${this.football},tennis:${this.tennis}}`;
}
}
const permPageData = [
{
"name": "name",
"visible": true,
},
{
"name": "age",
"visible": true
}, {
"name": "football",
"visible": true
}
];
const tableSearchModel = new Searchdata();
console.log(tableSearchModel.toString());
tableSearchModel.setFromJSON(permPageData);
console.log(tableSearchModel.toString());
output
{name:false,age:false,summer:false,winter:false,football:false,tennis:false}
{name:true,age:true,summer:false,winter:false,football:true,tennis:false}
Although it is quite different approach, I had found interface pretty interest.
.ts
interface Searchdata{
name: boolean;
age: boolean;
summer: boolean;
winter: boolean;
football: boolean;
tennis: boolean;
}
function searchDataNew(): Searchdata {
return {
name: false,
age: false,
summer: false,
winter: false,
football: false,
tennis: false
};
}
function searchDataToString(sd: Searchdata) {
return `{name:${sd.name},age:${sd.age},summer:${sd.summer},winter:${sd.winter},football:${sd.football},tennis:${sd.tennis}}`;
}
function arrayDataToObjData(arr: Array<{name:string,visible:boolean}>): Searchdata {
const obj: any = {};
arr.forEach(element => {
obj[element.name] = element.visible;
});
return obj;
}
const permPageData = [
{
"name": "name",
"visible": true,
},
{
"name": "age",
"visible": true
}, {
"name": "football",
"visible": true
}
];
const tableSearchModel: Searchdata = {
...searchDataNew(),
...arrayDataToObjData(permPageData2)
};
console.log(searchDataToString(tableSearchModel));
result
{name:true,age:true,summer:false,winter:false,football:true,tennis:false}
I'm trying to validate the parameters that come in the query of a get request, but for some reason, the validation pipe is unable to identify the elements of the query.
import {
Controller,
Post,
Query,
Body,
UseInterceptors,
Param,
Res,
Logger,
} from '#nestjs/common';
import { Crud, CrudController, Override } from '#nestjsx/crud';
import { OpenScheduleDto } from './open-schedule.dto';
#Crud(Schedule)
export class ScheduleController
implements CrudController<ScheduleService, Schedule> {
constructor(public service: ScheduleService) {}
get base(): CrudController<ScheduleService, Schedule> {
return this;
}
#Override()
async getMany(#Query() query: OpenScheduleDto) {
return query;
}
}
OpenSchedule.dto
import { IsNumber, IsOptional, IsString } from 'class-validator';
export class OpenScheduleDto {
#IsNumber()
companyId: number;
#IsNumber()
#IsOptional()
professionalId: number;
#IsString()
#IsOptional()
scheduleDate: string;
}
When I make a get request to http://localhost:3000/schedules?companyId=3&professionalId=1
I get unexpected errors:
{
"statusCode": 400,
"error": "Bad Request",
"message": [
{
"target": {
"companyId": "3",
"professionalId": "1"
},
"value": "3",
"property": "companyId",
"children": [],
"constraints": {
"isNumber": "companyId must be a number"
}
},
{
"target": {
"companyId": "3",
"professionalId": "1"
},
"value": "1",
"property": "professionalId",
"children": [],
"constraints": {
"isNumber": "professionalId must be a number"
}
}
]
}
That is because when you use #Query parameters, everything is a string. It does not have number or boolean as data types like json. So you have to transform your value to a number first. For that, you can use class-transformer's #Transform:
import { IsNumber, IsOptional, IsString } from 'class-validator';
import { Transform } from 'class-transformer';
export class OpenScheduleDto {
#Transform(id => parseInt(id))
#IsNumber()
companyId: number;
#Transform(id => id ? parseInt(id) : id)
#IsNumber()
#IsOptional()
professionalId?: number;
#IsString()
#IsOptional()
scheduleDate?: string;
}
Note though, that this is unsafe because e.g. parseInt('5abc010') is 5. So you might want to do additional checks in your transformation function.
I have following module which defines my angular app.
var ang = angular.module('mainapp', ['ngRoute']);
ang.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
$routeProvider.
when("/home", {
templateUrl: "homepage.html",
controller: "homeController"
}).
when("/quiz", {
templateUrl: "quizpage.html",
controller: "quizController"
}).
when("/", {
templateUrl: "index.html",
controller: "indexController"
});
//otherwise({ redirectTo: '/' });
}]);
ang.controller('indexController', function ($scope) {
$scope.btn = "Welcome"
$scope.Login = function () {
alert("Thanks ");
$location.path("home");
};
});
ang.controller('homeController', function ($scope) {
// initialize if you can
window.history.go(-1);
$scope.salutations = [{ name: "Mr", id: 1 }, { name: "Mrs", id: 2 }, { name: "Ms", id: 3 }, { name: "Jr", id: 4 }, { name: "Mister", id: 5 }, { name: "Dr", id: 6 }];
$scope.profile = {
name: "",
email: "",
contact: "",
division: "",
feedback: "",
};
$scope.submitInfo = function (profile) {
alert("Thanks " + profile.name + ". Lets get to the Quiz now.");
$location.path("quiz");
};
});
ang.controller('quizController', function ($scope) {
//initialize if you can
window.history.go(-1);
$scope.questions = [
{
"questionText": "Why is the sky blue?", "answers": [
{ "answerText": "blah blah 1", "correct": true },
{ "answerText": "blah blah 2", "correct": false },
{ "answerText": "blah blah 3", "correct": false }
]
},
{
"questionText": "Why is the meaning of life?", "answers": [
{ "answerText": "blah blah 1", "correct": true },
{ "answerText": "blah blah 2", "correct": false },
{ "answerText": "blah blah 3", "correct": false }
]
},
{
"questionText": "How many pennies are in $10.00?", "answers": [
{ "answerText": "1,000.", "correct": true },
{ "answerText": "10,000.", "correct": false },
{ "answerText": "A lot", "correct": false }
]
},
{
"questionText": "What is the default program?", "answers": [
{ "answerText": "Hello World.", "correct": true },
{ "answerText": "Hello Sunshine.", "correct": false },
{ "answerText": "Hello my ragtime gal.", "correct": false }
]
}
];
$scope.answers = {};
$scope.correctCount = 0;
$scope.showResult = function () {
$scope.correctCount = 0;
var qLength = $scope.questions.length;
for (var i = 0; i < qLength; i++) {
var answers = $scope.questions[i].answers;
$scope.questions[i].userAnswerCorrect = false;
$scope.questions[i].userAnswer = $scope.answers[i];
for (var j = 0; j < answers.length; j++) {
answers[j].selected = "donno";
if ($scope.questions[i].userAnswer === answers[j].answerText && answers[j].correct === true) {
$scope.questions[i].userAnswerCorrect = true;
answers[j].selected = "true";
$scope.correctCount++;
} else if ($scope.questions[i].userAnswer === answers[j].answerText && answers[j].correct === false) {
answers[j].selected = "false";
}
}
}
//console.log($scope.answers);
};
$scope.submitQuiz = function (quiz) {
alert("Congrats.");
$location.path("index");
};
});
I want to land user on index page with welcome button and upon clicking i want to take user to the homepage and when user fills info on home page it should go to quiz page.
But the app doesn't bind the controller to index page at all.
<!DOCTYPE html>
<html data-ng-app="mainapp">
<head>
<title>WinPrizes</title>
</head>
<body >
<div data-ng-controller="indexController">
<button ng-click="Login()">{{btn}}</button>
</div>
<script src="Scripts/angular.min.js"></script>
<script src="app/app.module.js"></script>
<script src="app/main.js"></script>
</body>
</html>
When the index page is opened it shows button text as {{btn}}. These are not partial templates . I just want to switch to different html pages as part of the navigation user clicks on a button in each page.
You're using ngRoute but you've not added the plugin library in index.html after the angulat.min.js In version 1.2 later angular-route.js has to be added separately it doesn't come inside main library. e.g.
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular-route.js">
</script>
Also, you're using $location service in all the controllers, so you've to pass that in controller function as a dependency.
You need ng-view directive on index.html to make routing work. And be careful that your views are partial views (containing partial html code). Also why you added window.history.go(-1); on initialisation of controller? Because it'll always go back to previous page onload o controller. You should add such code only inside some function which you're going to call on specific action/event.
Here's working plunker for your version of code:
https://plnkr.co/edit/ADWf012Q7mTVBR3svPYb?p=preview
I have the problem that two identical values with the same type do not equals in Typescript/Javascript.
What I want to do: I get data from a JSON and I want to join some data with other data of this JSON by id-attributes. The id's never match.
I've attached my files at the end. The problem is in getStationNameById():
even if "id" is 2 and "station.id" is 2, they never equals. They don't even equal with "== 2". I have absolutely no clue what the problem is. Due to my debug output both values are numbers.. but the result is ALWAYS false.
my component.ts
import {Component, OnInit} from '#angular/core';
import {DataService} from "../../services/data.service";
#Component({
selector: 'alle-stationen-view',
templateUrl: './src/html/alle-verbindungen-view.component.html',
styleUrls: [ './src/css/views-general.css', './src/css/alle-verbindungen-view.component.css']
})
export class AlleVerbindungenViewComponent implements OnInit {
private connections: any[];
private stations : any[];
constructor(private dataService : DataService) {};
ngOnInit(): void {
this.dataService.getData().subscribe(
data => this.dataHandler(data)
);
}
private dataHandler(data) {
let connections = data.connections || {};
let stations = data.stations || {};
this.stations = stations;
connections.forEach(function(connection) {
// TO DO: DOESNT WORK!
connection.fromStation = this.getStationNameById(connection.fromStationId);
connection.toStation = this.getStationNameById(connection.toStationId);
}, this);
this.connections = connections;
}
private getStationNameById(id : number) {
console.debug("---");
this.stations.forEach(function(station) {
// both have Constructor "Number"
console.debug("id.type="+id.constructor+", station.id.type="+station.id.constructor);
console.debug("id="+id+", station.id="+station.id);
console.debug("station.id==id : "+station.id == id)+""; // ALWAYS FALSE
console.debug("station.id===id: "+station.id === id+""); // ALWAYS FALSE
console.debug("id == 2:" +id==2); // ALWAYS FALSE
console.debug("station.id == 2:" +station.id==2); // ALWAYS FALSE
if (station.id === id) {
return station.name;
}
});
return "";
}
}
data.json
{
"data": {
"stations": [
{
"id": 1,
"name": "Hamburg Mitte"
},
{
"id": 2,
"name": "Hamburg Ost"
},
{
"id": 3,
"name": "Hamburg Hauptbahnhof"
}
],
"connections": [
{
"id": 1,
"fromStationId": 1,
"toStationId": 2,
"duration": 7
},
{
"id": 2,
"fromStationId": 2,
"toStationId": 1,
"duration": 7
},
{
"id": 3,
"fromStationId": 1,
"toStationId": 3,
"duration": 2
},
{
"id": 4,
"fromStationId": 3,
"toStationId": 1,
"duration": 2
},
{
"id": 5,
"fromStationId": 2,
"toStationId": 3,
"duration": 10
},
{
"id": 6,
"fromStationId": 2,
"toStationId": 2,
"duration": 10
}
]
}
}
console output
id.type=function Number() { [native code] }, station.id.type=function Number() { [native code] }
alle-verbindungen-view.component.ts:39 id=1, station.id=1
alle-verbindungen-view.component.ts:40 false
alle-verbindungen-view.component.ts:41 false
alle-verbindungen-view.component.ts:42 false
alle-verbindungen-view.component.ts:43 false
alle-verbindungen-view.component.ts:38 id.type=function Number() { [native code] }, station.id.type=function Number() { [native code] }
alle-verbindungen-view.component.ts:39 id=1, station.id=2
alle-verbindungen-view.component.ts:40 false
alle-verbindungen-view.component.ts:41 false
alle-verbindungen-view.component.ts:42 false
alle-verbindungen-view.component.ts:43 false
alle-verbindungen-view.component.ts:38 id.type=function Number() { [native code] }, station.id.type=function Number() { [native code] }
alle-verbindungen-view.component.ts:39 id=1, station.id=3
alle-verbindungen-view.component.ts:40 false
alle-verbindungen-view.component.ts:41 false
alle-verbindungen-view.component.ts:42 false
alle-verbindungen-view.component.ts:43 false
alle-verbindungen-view.component.ts:35 ---
You are doing it in wrong way.
In your code you are using console.debug("id == 2:" +id==2); which will compare "id==2" == 2 means you are comparing string with 2.
For example try this console.debug("id == 2:" +2==2); You will get false, because you are actually comparing "id == 2:2" == 2 which will always give you false.
Please let me know if you need more explanation.
EDIT :
In this statement we are using two operator + and == and + have higher precedence then ==. So firstly + get execute then == get execute.
I've found the solution. Due to I had wrongly debug output I searched at a wrong place for the bug. Now after I used parenthesis I received true results. I thought that the return in the forEach-function affected the whole method and not just this block. Therefore the method returned "" all the time. This works now:
private getStationNameById(id : number) {
let stationName : string = "";
this.stations.forEach(function(station) {
if ((station.id) === id) {
stationName = station.name;
}
});
return stationName;
}