I'm wondering whether it's possible to override the standard identifier with a custom one.
I've a simple struct:
struct MyUserData: Identifiable {
var userId: String
var userFirstName: String
var userLastName: String
}
However, the Identifiable protocol wont work without var id: ObjectIdentifier row inside the struct. At the same time, I don't want to use the "id" name. userId is also unique in my model (its a UUID). Is there a way to tell the identifiable protocol to accept "userId" instead of "id"?
Thanks!
You can use any Hashable as an id property required by Identifiable:
extension MyUserData: Identifiable {
var id: String { userId }
}
Unfortunately Identifiable requires a property called id. The easiest way to solve it is to use a computed property called id to your struct.
struct MyUserData: Identifiable {
var userId: String
var userFirstName: String
var userLastName: String
var id: String {
userId
}
}
I think you need this one:
import SwiftUI
struct MyUserData
{
var userId: String
var userFirstName: String
var userLastName: String
}
struct ContentView: View {
#State var arrayOfMyUserData: [MyUserData] = [MyUserData]()
var body: some View {
List
{
ForEach(arrayOfMyUserData, id: \.userId) { item in
Text("FirstName: " + item.userFirstName) + Text(" LastName: " + item.userLastName)
}
}
.onAppear() {
arrayOfMyUserData = [MyUserData(userId: "userId1", userFirstName: "willy", userLastName: "will"),
MyUserData(userId: "userId2", userFirstName: "bob", userLastName: "mccarthy"),
MyUserData(userId: "userId3", userFirstName: "james", userLastName: "rodriguez")
]
}
}
}
Or you can use this:
struct MyUserData
{
let userId: UUID = UUID()
var userFirstName: String
var userLastName: String
}
Related
This was my ModelsConfig
class ModelsConfig: ObservableObject {
#Published var lists: [ListModel] = []
#Published var reminders: [Reminder] = []
}
and those were my models
struct ListModel: Hashable {
var color: String
var text: String
var reminders: [Reminder]
}
struct Reminder: Hashable {
var title: String
var notes: String
var date: Date
var index: Int
var list: ListModel
}
Before I was able to reach indices in this View as this with the help of ModelsConfig
struct ListDetailView: View {
#Binding var selectedIndex: Int
#State var isSelected: Bool = false
#EnvironmentObject var config : ModelsConfig
ForEach(config.lists[selectedIndex].reminders.indices, id: \.self) { reminderIndex in
HStack {
Button(action: {
DispatchQueue.main.asyncAfter(deadline: .now() + 1){
deleteReminder(at: reminderIndex)
}
}, label: {
// ReminderCell(reminder: list.reminders[reminderIndex])
ReminderCell(reminder: config.lists[selectedIndex].reminders[reminderIndex])
})
}
.padding(.bottom)
}
Now, I am trying to reach the same indices with the help of core data as this
#FetchRequest(sortDescriptors: [])
var list: FetchedResults<CDListModel>
ForEach(list[selectedIndex].reminders.indices , id: \.self) { reminderIndex in
HStack {
Button(action: {
DispatchQueue.main.asyncAfter(deadline: .now() + 1){
deleteReminder(at: reminderIndex)
}
}, label: {
ReminderCell(reminder: list[selectedIndex].reminders[reminderIndex])
})
}
.padding(.bottom)
}
But it does not allow me to do so. How can I reach to indices inside the coredata?
In Core Data relationships are (NS)Sets. For performance reasons they are unordered.
The easiest solution is to convert the set to an array
ForEach((list[selectedIndex].reminders.allObjects as! [CDReminder]).indices , id: \.self) { reminderIndex in
Consider to declare the relationship as native Set<CDReminder>. Swift Sets are a sequence and got indices.
Say I have the following json files:
const obj1 = {
en: {
user: {
name: "John"
}
},
language: "en"
}
const obj2 = {
ru: {
user: {
name: "Vladimir"
}
},
language: "ru"
}
To retrieve these objects with NODE I will use the following code:
let en_name = obj1.en.user.name; //returns John
let ru_name = obj2.ru.user.name; //returns Vladimir
Is it possible to use the object language, and call the user.name based on the language? maybe something like this, which doesn't work:
let lang = obj.language
let anyName = language.user.name;
UPDATE:
I want to access data.jvProfiles.ANY_LANGUAGE.title as shown in the figure:
console.log(data.preferredLanguage); //Returns "nl"
let title = data.jvProfiles.nl.title; //Ruturns "Database Marketeer"
console.log(data.jvProfiles.data[data.preferredLanguage]); //gives error
console.log(data.jvProfiles.data[data.preferredLanguage].title); //gives same error
TypeError: Cannot read property 'nl' of undefined
SOLUTION:
console.log(data.jvProfiles[data.preferredLanguage].title);
You can use square brackets notation to access an object property dynamically:
const obj = {
en: {
user: {
name: "John"
}
},
language: "en"
}
const name = obj[obj.language].user.name
console.log(name)
Actually, I'm a newbie to graphQL so I wasn't able to pass parameters rightly in function updateMessage() in graphiQL. I'm trying to update the database using
mutation {
createMessage(input: {
author: "Pawan",
content: "hope is a dangerous thing",
}) {
id,content,author,
}
updateMessage(id:{cfe934d60b9997a4507e},input:{
author: "Pawan",
content: "hope is a dangerous thing",
})
}
but the error is displayed as
{
"errors": [
{
"message": "Syntax Error: Expected :, found }",
"locations": [
{
"line": 8,
"column": 40
}
]
}
]
}
Beside I'm also not able to show fakeDatabase .Can I do that ?
if yes How can I show every time I add a message to the fakeDatabase?
mutation.js
var express = require('express');
var graphqlHTTP = require('express-graphql');
var { buildSchema } = require('graphql');
// Construct a schema, using GraphQL schema language
var schema = buildSchema(`
input MessageInput {
content: String
author: String
}
type Message {
id: ID!
content: String
author: String
}
type Query {
getMessage(id: ID!): Message
}
type Mutation {
createMessage(input: MessageInput): Message
updateMessage(id: ID!, input: MessageInput): Message
}
`);
// If Message had any complex fields, we'd put them on this object.
class Message {
constructor(id, {content, author}) {
this.id = id;
this.content = content;
this.author = author;
}
}
// Maps username to content
var fakeDatabase = {};
var root = {
getMessage: function ({id}) {
if (!fakeDatabase[id]) {
throw new Error('no message exists with id ' + id);
}
return new Message(id, fakeDatabase[id]);
},
createMessage: function ({input}) {
// Create a random id for our "database".
var id = require('crypto').randomBytes(10).toString('hex');
fakeDatabase[id] = input;
return new Message(id, input);
},
updateMessage: function ({id, input}) {
if (!fakeDatabase[id]) {
throw new Error('no message exists with id ' + id);
}
// This replaces all old data, but some apps might want partial update.
fakeDatabase[id] = input;
return new Message(id, input);
},
};
var app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
console.log(fakeDatabase)
app.listen(4000, () => {
console.log('Running a GraphQL API server at localhost:4000/graphql');
});
On your mutation updateMessage try updating the parameters and send $id as a string instead of an object, like:
updateMessage(id:"cfe934d60b9997a4507e",input:{
author: "Pawan",
content: "hope is a dangerous thing",
})
The issue is that mutation updateMessage requires an ID and MessageInput, but you're sending Object and MessageInput.
I want to add a new field with a variable name to an object in the DB : meaning, I don't know the name of the field, but it's held in a variable "newFieldName".
So what I want to do is basically this:
var newFieldName = "world";
db.bios.update(
{ _id: 3 },
{ $set: {
"hello."+newFieldName: "Amazing Grace"
}
}
)
After the update, I expect the object "hello" to have a field "world" with the value "Amazing Grace".
but this doesn't even compile, let alone work. How can I do it?
You can use an intermediary object:
var update = { $set : {} };
update.$set['hello.' + newFieldName] = 'Amazing Grace';
db.bios.update({ _id : 3 }, update, ...)
var some_object = Posts.findOne({...});
var new_value = 1337;
Posts.update(another_object._id,
{$set: {
[some_object.some_field]:new_value,
}
}
);
To answer #yossale & #robertklep, the inline version is in fact possible using an expression and the comma operator:
var newFieldName = "world", o;
db.bios.update(
{ _id: 3 },
{$set:(o = {}, o["hello."+newFieldName] = "Amazing Grace", o)}
)
Simple is that:
var newFieldName = "world";
db.bios.update(
{ _id: 3 },
{ $set: {
["hello."+newFieldName]: "Amazing Grace"
}
}
);
#Andy's answer solved my problem.
I have a field which will be one of two objects (either a stored credit card or a given credit card):
payment_method:
cc_token: String
security_code: String
payment_method:
number: String
security_code: String
expiration_month: Number
expiration_year: Number
billing_address:
_type: String
first_name: String
last_name: String
address_line1: String
address_line2: String
zip_code: String
city: String
state: String
phone_number: String
I know the passed data is going to match one of these, but not both. Is there a way of specifying some sort of OR construct for the validation?
You didn't provide examples of your containing schema, but, there are a number of ways to validate.
One thing I did was specified the "mixed" type for the Schema allowing any type to be used for the field that could contain either type.
function validatePaymentMethod(value) {
if (!value) { return false; }
// put some logic that checks for valid types here...
if (value.cc_token && value.billing_address) {
return false;
}
return true;
}
var OrderSchema = new mongoose.Schema({
payment_method : { type: mongoose.Schema.Types.Mixed,
validate: [validatePaymentMethod, 'Not valid payment method'] }
});
var Order = mongoose.model("Order", OrderSchema);
var o = new Order();
o.payment_method = { cc_token: 'abc', billing_address: 'Street' };
o.validate(function(err) {
console.log(err);
});
The others are documented here.