Storing static and common data in React Native - javascript

Hello I am creating a dictionary app in React Native and I simply want to store an array of JSON blobs that would hold the definitions of each word.
I would very much like to avoid having to hardcode the data and want my code to be DRY!
Sample JSON blob:
[
{
"word": "triangle",
"definition": "a plane figure with three straight sides and three angles.",
"type": "noun"
},
{
"word": "square",
"definition": "a plane figure with four equal straight sides and four right angles.",
"type": "noun"
},
{
"word": "circle",
"definition": "a round plane figure whose boundary (the circumference) consists of points equidistant from a fixed point (the center).",
"type": "noun"
}
]
What is the best strategy to store this data so that it is:
Can be bookmarked by the user
Clean and easy to change and separated from other files
How it can be accessed by my React components
I think Relational DataBases are the best approach but I have difficulty figuring out how I would seed the database with data. And which library on React Native to use for a Relation Database.
Thank you for reading my question.

You can do what you are describing using Realm with the following schema:
let EntrySchema = {
name: 'Entry',
primaryKey: 'word',
properties: {
word: 'string',
definition: 'string',
type: 'string'
}
};
let BookmarkListsSchema = {
name: 'BookmarkList',
properties: {
bookmarks: {type: 'list', objectType: 'Entry'}
}
};
let realm = new Realm({schema: [EntrySchema, BookmarkListsSchema]});
You can pre-populate a Realm file with all of your dictionary entries and bundle it with your app, or alternatively you could download this file or JSON and initialize your db when starting the app.
To create/add bookmarks:
// create your list once
var bookmarkList;
realm.write(() => {
bookmarkList = realm.create('BookmarkList');
});
// add entry for 'triange' to bookmarks
realm.write(() => {
let triangeEntry = realm.objectForPrimaryKey('Entry', 'triangle');
bookmarkList.bookmarks.push(triangleEntry);
});

Related

how to add more words in the Toxicity classifier

is there a way i can add more words to the
toxicity classifier ?
this is what i am using at the moment just a basic script
from the example given in the github page
// The minimum prediction confidence.
const threshold = 0.9;
// Load the model. Users optionally pass in a threshold and an array of
// labels to include.
toxicity.load(threshold).then(model => {
const sentences = ['you suck'];
model.classify(sentences).then(predictions => {
// `predictions` is an array of objects, one for each prediction head,
// that contains the raw probabilities for each input along with the
// final prediction in `match` (either `true` or `false`).
// If neither prediction exceeds the threshold, `match` is `null`.
console.log(predictions);
/*
prints:
{
"label": "identity_attack",
"results": [{
"probabilities": [0.9659664034843445, 0.03403361141681671],
"match": false
}]
},
{
"label": "insult",
"results": [{
"probabilities": [0.08124706149101257, 0.9187529683113098],
"match": true
}]
},
...
*/
});
});
https://github.com/tensorflow/tfjs-models/tree/master/toxicity
You can add more words in the array sentences for the predictions:
const sentences = ['you suck', 'add whatever you want'];
However, you cannot change the labels of the model. You can only do so during the training of the model. The toxicity model was trained using python before being ported to js. So you can only change the labels by retraining the python model.

API request: better approach to set a Enum value

The Backend has an end-point called api/Options/GetEmailMessageTemplate, it returns objects which has this schema:
{
messageType: string, Enum: [ ConfirmationEmail,
ConfirmationTransaction, RecoveryPassword, SetupAdminAccount, ConfirmationApiKey, ConfirmationDepositTransaction ]
language: string, Enum: [ En, Ru, Zh, Es, Et ]
subject: string,
template: string,
isUsed: boolean
}
e.g. response:
{
"messageType": 1,
"language": "En",
"subject": "string",
"template": "string",
"isUsed": true
}
here is another end-point to edit it api/Options/Options/UpdateEmailMessageTemplate which consumes json with the same schema as above. messageType might be either number of an element in Enum or Enum value (e.g. 'ConfirmationEmail')
On the Frontend to list all the data and be able to change it I came up with this approach:
I made an strictly ordered array:
messageTypes: [
{
name: 'Confirmation Email',
success: false,
},
...
]
Success is required to show if the change of this template was successful
I get messageTypeas a number id from backend, I just used it as index in my array (so, for this to work my array must be ordered in the exactly same way Enum of that field is ordered ), to get the name of that messageType and operate with success field
3.api/Options/Options/UpdateEmailMessageTemplate gets messageType using index of the currently being edited element (indexOf)
While this approach worked as was expected I can't help but think there was a better way to handle this.
I would like to hear if there are better practices to handle that
Based on my understanding, you are wanting a way to work with a friendly list of values as well as their id's. One approach would be to create two separate classes. This would enable you to feed the raw response to a single model and you can add whichever methods are needed to translate id > name or the other way around.
You could probably get a little more fancier and use get/set but I'm still a little foggy on the requirements. But, here's an approach that I would take:
/**
* Create a class that knows how to translate it
* Bonus points: this could be populated via your endpoint
* that returns your enum list so you don't have to keep
* updating it if there's a change on the backend
*/
class MessageType {
constructor(messageType) {
this.id = messageType;
const messageTypes = [
'ConfirmationEmail',
'ConfirmationTransaction',
'RecoveryPassword',
'SetupAdminAccount',
'ConfirmationApiKey',
'ConfirmationDepositTransaction'
];
this.name = messageTypes[this.id];
}
}
/**
* Create a class / model for your response.
* This will enable you to add any methods
* needed for translating things how you need
* them. For example, you might want a method
* to convert your model into what the backend
* expects.
*/
class MessageTemplate {
constructor(response) {
this.messageType = new MessageType(response.messageType);
this.language = response.language;
this.subject = response.subject;
this.template = response.template;
this.isUsed = response.isUsed;
}
getJsonPayloadForBackend() {
const payload = { ...this };
payload.messageType = payload.messageType.id;
return payload;
}
}
// Usage
const template = new MessageTemplate({
"messageType": 2,
"language": "En",
"subject": "string",
"template": "string",
"isUsed": true
});
console.log(template);
console.log('data to send to backend', template.getJsonPayloadForBackend())

How to structure various interdependent Schemas in mongoose OR how to use 'reference' properly?

I'm currently working on a vocabulary application using node.js, Express, MongoDB and mongoose.
My aim: Putting out translations for various languages depending on the choices made in the front-end (E. g.: German > English, English > Portuguese etc.)
Main problem: Interdependent Schemas. The translation of a word stored in WordSchema depends on the language represented by the LanguageSchema.
For me, there appear two different ways on how to structure the relevant Schemas:
1.
There is one Schema representing the language (e.g. German, Englisch,...). It stores several words according to the language. Because Word represents another Schema it is referenced to the WordSchema inside the LanguageSchema. The problem which appears here is that the values of the word depend on the chosen language.
var Schema = mongoose.Schema;
var LanguageSchema = new Schema({
language: String, // 'German'
words: [{type: Schema.ObjectId, ref: 'Word'}]
// word: 'Haus' instead of e. g. 'house'
});
module.exports = mongoose.model('Language', LanguageSchema);
var WordSchema = new Schema({
name: String // 'house', 'Haus', 'casa' depending on the language
});
module.exports = mongoose.model('Word', WordSchema);
2. I could solve this by using just the WordSchema and adding all the languages which exist as a property and add the according translation of the word. But this doesn't seem the best working solution for me as I won't translate the words into all languages right from the beginning. So there just should be stored those translations for a word where there actually exists a translation.
LanguageSchema
var Schema = mongoose.Schema;
var LanguageSchema = new Schema({
language_name: {type:String}, // English
language_code: {type:String} // en
});
module.exports = mongoose.model('Language', LanguageSchema);
In Word Schema , you need to push objects with word_name and word_language
WordSchema
var WordSchema = new Schema({
words:[{
word_name:{type:String},
word_language:{type:String}
}]
});
module.exports = mongoose.model('Word', WordSchema);
Example : Language in Database
languages : [
{
"_id":"54ef3f374849dcaa649a3abc",
"language_name":"English" ,
"language_code":"en"
},
{
"_id":54ef3f374849dcaa649a3asd",
"language_name":"Portuguese" ,
"language_code":"pt"
},
{
"_id":54ef3f374849dcaa649a3xxx",
"language_name":"German" ,
"language_code":"de"},
]
Example : Words in Database
words:[
{
word:[
{
"_id":"54ef3f374849dcaa649azzz",
"word_name":"Friend" ,
"word_language":"English"
},
{
"_id":"54ef3f374849dcaa6491111",
"word_name":"Amigo" ,
"word_language":"Portuguese"
},
{
"_id":"54ef3f374849dcaa649a233",
"word_name":"Freund" ,
"word_language":"German"
},
]
},
{ word: [...] },
{ word: [...] },
{ word: [...] },
{ word: [...] }
]
from frontend you have to pass 3 parameters
word , input_language , output_language
Example : You want "Friend" meaning from English to Portuguese
so in this case :
word="Friend" , input_language="English" ,
output_language="Portuguese"
Now Applying Mongoose Find Query and search Word in WordSchema
Word.findOne({word_name:{ $regex:word, $options: "$i" },word_language:input_language},function(err,result){
if(err){ return err;}
if(!err && result){
// now you have to use underscore.js and find out result by output language
// http://underscorejs.org
// . npm i --save underscore
var outputObj= _.find(result.word, { word_language :output_language});
res.json(outputObj);
}
})

React Native - Dynamic Image Source

I'm trying to loop through the SOURCE array with the map method, but I keep getting this error:
Unknown named module: '../images/one.jpeg'
Anyone know why this is happening? The file path in the require is definitely correct.
var SECTIONS = [
{
title: 'One',
fileName: 'one.jpeg',
},
{
title: 'Two',
fileName: 'two.jpeg',
},
{
title: 'Three',
fileName: 'three.jpeg',
},
{
title: 'Four',
fileName: 'four.jpeg',
},
];
{SECTIONS.map((section, i) => (
<CategoryCard
key={i}
source={require(`../images/${section.fileName}`)}
title={section.title}
/>
))}
I don't think this is possible because react native needs to know what to bundle ahead of time (AFAIK). However, you can require all the files in your array:
var SECTIONS = [
{
title: 'One',
file: require('../images/one.jpeg'),
},
{
title: 'Two',
file: require('../images/two.jpeg'),
},
{
title: 'Three',
file: require('../images/three.jpeg'),
},
{
title: 'Four',
file: require('../images/four.jpeg'),
},
];
{SECTIONS.map((section, i) => (
<CategoryCard
key={i}
source={section.file}
title={section.title}
/>
))}
You can't use dynamic links. The best hack that i found to solve this is this:
var SECTIONS = {
One: {
title: 'One',
file: require('../images/one.jpeg'),
},
Two: {
title: 'Two',
file: require('../images/two.jpeg'),
},
Three: {
title: 'Three',
file: require('../images/three.jpeg'),
},
Four: {
title: 'Four',
file: require('../images/four.jpeg'),
},
};
{SECTIONS.map((section, i) => (
<CategoryCard
key={i}
source={section.file}
title={section.title}
/>
))}
That way, you can just use the files and if you have some kind of dynamic image selection, you can just use something like this
<Image source={SECTIONS[image.type]} />
try opening the file in separate browser using direct URL something like
http://<><>/imgages/one.jpg
You can also do something like this as well:
One working example for displaying dynamic images using react :
Example Click Here
Got a working solution, though not recommended for large images, works perfectly for (a lot of)small images.
Steps:
Convert the icon(s) to base64 string(s).
Create a JSON file with filename as the keys and the base64 strings as values.
(You can also store them to a local database)
e.g.
ImageData.json
{
"icon1": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQ.......==",
"icon2": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQ.......=="
}
3.Import the json file to the place where you require the images dynamically.
e.g.
const imageData = require("./images/ImageData.json")
4: Get/generate the key/filename at runtime. and get the image source.
e.g.
const imageSrc = imageData[keyname]
5: Generate a image dynamically at runtime.
e.g.
<Image style={{ width: 70, height: 70, resizeMode: Image.resizeMode.contain }} source={ uri: imageSrc } />
Done..
Extra..
Written a helper python script to automate the json file creation.
import base64
import os
directory = os.fsencode('.')
with open('ImagesData.json', 'wb') as jsonFile:
jsonFile.write(bytes('{', 'utf-8'))
written = False
for file in os.listdir(directory):
filename = os.fsdecode(file)
if filename.endswith('.png'):
with open(filename, "rb") as image_file:
if written:
jsonFile.write(bytes(',\n','utf-8'))
encoded_string = base64.b64encode(image_file.read())
jsonFile.write(bytes(('"' +filename+ '":'), 'utf-8'))
jsonFile.write(bytes('"data:image/png;base64,', 'utf-8') + encoded_string + bytes('"', 'utf-8'))
written = True
jsonFile.write(bytes('}', 'utf-8'))
Copy the script to the image folder and run the script (requires python 3.6).
A json file will the created with image name as key and base64 string as values.
Copy the file to project and use (You can delete the images after that).
Use the json file as mentioned above.
I had the same problem but my situation was a little different. I had an array of different objects that needed dynamic images. I was already mapping the array, but I needed to match the images to that array based off of name. It was a little hacky, but this is how I went about it.
First, in my parent component I created a function to render a component for my array of objects. I passed the objects data into a prop called "object".
In my case I knew what my data was and I needed to match the corresponding image to the object that was being pulled off of an external api that I was grabbing my data from.
renderObjects() {
return this.state.objects.map(object => (
<ObjectListDetail
key={object.id}
next
props={this.props}
object={object}
/>
));
}
In my ObjectListDetail component, I created a variable called icons, which was another array of objects. This time, I created a name property that would match the object being passed to the component from the parent and then had a second key called source in which I provided the path to the image. It went something like this.
var icons = [
{ name: "BTC", source: Images.btc },
{ name: "ETH", source: Images.eth },
{ name: "ETC", source: Images.etc },
{ name: "ZRX", source: Images.zrx },
{ name: "USDC", source: Images.usdc },
{ name: "LTC", source: Images.ltc },
{ name: "BCH", source: Images.bch },
{ name: "USD", source: Images.usd }
];
NOTE *** I had already required all of my images into a separate file for my entire app and imported them at the top.
I then created a variable called imgSrc and filtered the result to match the name of the object i was passing to the child component.
var imgSrc = icons.filter(
icon => icon.name === props.wallet.name
)
I then created an Image component and in the source requirement I called the result of the filter and pointed it to the source.
<Image source={imgSrc[0].source} />
That is how I achieved dynamic image rendering within my application.
Its probably not the best way to do things, and I am still kinda new at this, but I would love any criticism

Reuse properties from a remote JSON schema, at the same level of the original schema

I have a remote schema "person.json", saved on another file.
{
"id":"#person",
"type":"object",
"properties": {
"name": {"type":"string"},
"gender": {
"type":"string",
"enum":["m", "f"]
},
"age": {"type":"number"}
},
"additionalProperties": false
}
And I have a "man.json" schema, being this one my original schema.
{
"id":"#man",
"type":"object",
"$ref":"person.json",
"properties": {
"beard":"boolean",
"moustache":"boolean"
},
"required": ["name"],
"additionalProperties": false
}
I want to use the properties: "name, gender, etc" from person.json at the same level as the properties: "beard, moustache" from man.json.
Example for validation
{
name: 'John',
gender: 'm',
age: 29,
beard: false,
moustache: true
}
I want to validate the previously shown example, as you see, with all the properties at the same level (not nested).
Is this possible? If yes, how? Thank you very much.
João
You want to use the allOf keyword, combined with $ref:
{
"id": "/schemas/man.json",
"allOf": [{"$ref": "person.json"}],
...
}
(Note: This is v4. In v3, the same thing was called extends.)
In plain English, it says "Every instance following Man schema must also follow the Person schema".
The bigger issue is in fact your use of additionalPropeties. Since person.json bans additional properties, any instance with a "beard" property is actually not a valid Person. If you're going to be extending Person, I advise you remove the constraint banning additional properties.
(Note: this behaviour is the subject of some conflict in the JSON Schema community, but this is what's in the specs.)
I'm guessing a piece of data cannot satisfy two schemas at once, so you'll need to create a third schema which combines them and validate against that.
var personSchema = JSON.parse(person_json);
var manSchema = JSON.parse(man_json)
for (var personProp in personSchema.properties) {
manSchema.properties[personProp] = personSchema.properties[personProp];
}
var manPersonSchema = JSON.stringify(manSchema);

Categories