Consider classes
Product = {
variations: [],
properties: []
}
Property = {
values: []
}
Variation = {
values: []
}
Value = {
simpleString:""
}
On the client (in JS) I first create products with properties and the possible values each property may have.
After that I create variations. Each of them can have a set of several values. But it only can "use" the values, which do already exist for properties.
In the next step, I move that product-object over to rest api.
While in JS the values used in a variation points to the original object in the product property, after encoding to JSON and backwarts to stdClass in PHP behind the restful service, this link gets lost.
Of course I could give them IDs on my own and call them temp_id or so. Hacky.
How would pros do it?
PHP
I simply deserialize the incomming JSON $object = json_decode($json); and use RedBeans and Piped to manage that end. What it does is mainly just moving through the properties and create objects with ..._id == null (then they get a unique ID).
Let's say I would do it manually:
I'd walk through the properties and store each value-object into the MySQL-db. Say
{
value_id: null,
simpleString: 'Green'
}
After storing it will have the value_id = 111.
Now I walk through the variations. One of these uses the Green-Value. But since this value will also be
{
value_id: null,
simpleString: 'Green'
}
how could I identify them? The string, of course, is too weak - no one could consider that. As mentioned above, I could give them temporary IDs. But surely there is a better way.
Related
I'm mapping an array and based on data i'm pushing Option elements into an array as follows
let make_children: any | null | undefined = [];
buyerActivityResult && buyerActivityResult.simulcastMyAccount.data.map((item: { make: {} | null | undefined; }, key: any) => {
make_children.push(
<Option key={key}>{item.make}</Option>
);
});
Following data array has several objects and these objects have an attribute called model.
buyerActivityResult.simulcastMyAccount.data
I want to prevent pusing Options to my array if the attribute model has duplicate data. It only has to push once for all similar model values.
How can i do it?
I tried something like this
buyerActivityResult && buyerActivityResult.simulcastMyAccount.data.map((item: { model: {} | null | undefined; }, key: any) => {
model_children.indexOf(item.model) === -1 && model_children.push(
<Option key={key}>{item.model}</Option>
);
});
But still duplicate values are being pushed into my array.
Its difficult to tell what you are trying to achieve but it looks like a map may not be the right tool for the job.
A map returns the same sized length array as that of the original array that you are calling map on.
If my assumptions are correct, your buyerActivityResult.simulcastMyAccount.data array has duplicate values, and you want to remove these duplicates based on the model property? One way to achieve this would be to use the lodash library for this, using the uniq function:
const uniqueResults = _.uniq(buyerActivityResult.simulcastMyAccount.data, (item) => item.model);
The Array.prototype.map() method is supposed to be used for manipulating the data contained into the array performing the operation. To manipulate data from other variables I recommend to use a for-loop block.
If item.model is an object, the function Array.prototype.indexOf() always returns -1 because it compares the memory address of the objects and does not do a deep comparison of all properties values.
The usual solution to remove duplicate data from an array is converting the Array into a Set then back to an Array. Unfortunately, this works only on primary type values (string, number, boolean, etc...) and not on objects.
Starting here, I will review your source code and do some changes and explain why I would apply those changes. First of all, assuming the make_children array does not receive new attribution later in your code, I would turn it into a constant. Because of the initialization, I think the declaration is overtyped.
const make_children: any[] = [];
Then I think you try to do too much things at the same time. It makes reading of the source code difficult for your colleagues, for you too (maybe not today but what about in few weeks...) and it make testing, debugging and improvements nearly impossible. Let's break it down in at least 2 steps. First one is transforming the data. For example remove duplicate. And the second one create the Option element base on the result of the previous operation.
const data: { make: any }[] = buyerActivityResult?.simulcastMyAccount?.data || [];
let options = data.map((item) => !!item.model); // removing items without model.
// Here the hard part, removing duplicates.
// - if the models inside your items have a property with unique value (like an ID) you can implement a function to do so yourself. Take a look at: https://stackoverflow.com/questions/2218999/remove-duplicates-from-an-array-of-objects-in-javascript
// - or you can use Lodash library like suggested Rezaa91 in its answer
options = _.uniq(data, (item) => item.model);
Now you only have to create the Option elements.
for (var i = 0; i < options.length; i++) {
model_children.push(<Option key={i}>{options[i].model}</Option>);
}
// OR using the Array.prototype.map method (in this case, do not declare `model_children` at the beginning)
const model_children:[] = options.map((opt:any, i:number) => <Option key={i}>{opt.model}</Option>);
Despite the lack of context of the execution of the code you provided I hope my answer will help you to find a solution and encourage you to write clearer source code (for the sake of your colleagues and your future self).
PS: I do not know anything about ReactJs. forgive me my syntax mistakes.
I have two arrays src and update. Both contain objects. Incoming JSON from an API, the objects in the arrays follow the same structure (see below).
I want to compare src against update and add/remove/update items in src that have represented changes in update.
My current process involves iterating both arrays and comparing items using JSON.stringify(), doing multiple passes. Pass one to add, pass two to delete, and pass three to detect changes for replacement (I replace the entire object rather than the fields).
Is there an easier/better way?
Is there a generic utility to help facilitate for this or must I write my own diff detection system?
EDIT: The objects inside the arrays look like (but not limited to):
[
{
id: String,
summary: String,
updates: [
{
date: String,
title: String
},
{ Repeated }
]
},
{ Repeated }
]
As Ali pointed out lodash _.isEqual is a good utility method for this.
Check out https://lodash.com/docs/4.17.4#isEqual
Lodash is really good for helper functions and dealing with data.
If I understand your question correctly both your 'updates' and 'src' array have the same structure - objects with two properties, 'date' and 'title'. You can compare them with nested loops. For example, something like this might be helpful...
updates.forEach(function(u) {
src.forEach(function(s) {
if (s.date === u.date && s.title === u.title) {
// You have a match
}
});
});
I presume you want to identify partial matches, so you can add/replace the if-condition in the inner loop and amend the src array accordingly...
if (s.date === u.date && s.title !== u.title) {
// same date, different title, so...
// change the title of the current
// item from the 'src' array;
s.title = u.title;
}
Or use if-else-if conditions as needed. Regardless, although it's not quite clear from your question which array should be the outer-loop and which should be the inner, the nested 'forEach' loops above will compare each item in the 'updates' array against every item in the 'src' array.
I hope that helped. :)
So I created a property in the root element of my qml and filled it with JavaScript as a 2d array. I did it this way:
property var cars: {
var carList = new Array(root.numberOfCars)
for (var i=0;i<root.numberOfCars;i++) {
var carProperties = new Array(numberOfCarProperties);
carProperties[root.currentStation] = -1;
carProperties[root.score] = 100;
carProperties[root.numberOfErrors] = 0;
carProperties[root.hasProblem] = false;
carProperties[root.errorScore] = 0;
carProperties[root.finished] = false;
carList[i] = carProperties;
}
return carList;
}
The values of the array will be changed as the program runs via JavaScript.
I want to display the values of this 2d array in a table and update them when they're changed, in addition to some action buttons that affect the values of the array at it's own row.
I'm just a noob at QML and programming in general, so if this is a very basic question please tell me where can I learn more, since I've found few resources online to learn QML.
Plain arrays are not the ideal solution if you intend to visualize the data. QML views can use arrays as models, but this is inefficient if you want to reflect internal changes. You either have to force update of the entire view, recreating all view delegates instead of just updating the changed value, or you will have to implement your own mechanism to update changes.
The easiest thing to use would be a ListModel element, and rather than implementing properties as an array (bad idea anyway) you can implement them as list element properties:
ListModel {
id: carList
ListElement {
currentStation: -1
score: 100
numberOfErrors: 0
// ...
}
ListElement {
// ...
}
}
The model can be populated declarative as above, or imperatively:
carList.append({"currentStation": -1, "score": 100, ...})
You also have the usual index access, property access and so on, just scroll through the doc to get an idea of the interface.
The benefit of this is you will get efficient automatic updates in the view. So you just set up a view and implement a delegate that will serve to visualize and manipulate the data.
I'm trying to retrieve a nested object based on a nested nested id.
So my object is as follows
object = {
1: {
feature: {id:"1012"},
}
2: {
feature: {id:"3032"}
}
}
I have an id and I need to retrieve the corresponding object or to be more specific the object id. The object is a lot more complex but above shows the values that I need to retrieve.
I don't have much experience in JavaScript so am unsure how to achieve this. I've tried using Jquery's attribute selectors but have not been successful.
Any help would be appreciated.
Thanks.
if your "id" is mean like 1 or 2
do it like this:view it in JSFiddle
var obj = {
1: {
feature: {id:"1012"}
},
2: {
feature: {id:"3032"}
}
}
var getById = function(id){
return obj[id];
}
alert(getById(1).feature.id);
another way,if your id means like '1012','3032'
do it like this:view it in JSFiddle
my post about the Map in js
If I'm understanding the question correctly you are trying to use the id property of the object in each feature property to get the key (1, 2, etc) from object? So if you entered "1012" you would get back 1, if you entered "3032" you would get 2, etc?
If so this would do it:
var object = {
1: {
feature: {id:"1012"}
},
2: {
feature: {id:"3032"}
}
},
getIdByFeatureId = function (featureId) {
var id,
subObject;
// loop through each property of the object
for (id in object) {
// protect ourselves in case someone has tampered with Object.prototype
if (object.hasOwnProperty(id)) {
subObject = object[id];
if (subObject.feature.id === featureId) {
return id;
}
}
}
// none found? return null.
return null;
};
getIdByFeatureId("3032"); // returns 2
getIdByFeatureId("1012"); // returns 1
getIdByFeatureId("90210"); // returns null
You can play with the code in this fiddle.
Numbers stored as strings can be a pain, and often lead to confusion in how one need to call a function like this. One thing you might notice is I used the === strict equal operator. This only returns true if both values are exactly the same, including their type. It's good practice to use strict comparison operators unless you absolutely can't. It is also slightly faster since it doesn't have to coerce the values into a like type. But that means that you must pass a string into the function in order for it to match. You could use the non-strict equals == if you need it to be more flexible. If all of the feature ids are numeric (and none of them have leading zeros) and you have the ability to, I would change the feature ids to be actual numbers so you can keep it more intuitive by just passing in a number instead of a string representation of a number: getIdByFeatureId(3032); while keeping the strict comparison.
I am working on an app that heavily uses JavaScript. I am attempting to include some object-oriented practices. In this attempt, I have created a basic class like such:
function Item() { this.init(); }
Item.prototype = {
init: function () {
this.data = {
id: 0,
name: "",
description: ""
}
},
save: function() {
alert("Saving...");
$.ajax({
url: getUrl(),
type: "POST",
data: JSON.stringify(this.data),
contentType: "application/json"
});
}
}
I am creating Item instances in my app and then saving them to local storage like such:
Item item = new Item();
window.localStorage.setItem("itemKey", JSON.stringify(item));
On another page, or at another time, I am retriving that item from local storage like such:
var item = window.localStorage.getItem("itemKey");
item = JSON.parse(item);
item.save();
Unfortunately, the "save" function does not seem to get reached. In the console window, there is an error that says:
*save_Click
(anonymous function)
onclick*
I have a hunch that the "(anonymous function)" is the console window's way of saying "calling item.save(), but item is an anonymous type, so I am trying to access an anonymous function". My problem is, I'm not sure how to convert "var item" into an Item class instance again. Can someone please show me?
Short answer:
Functions cannot be serialized into JSON.
Explanation:
JSON is a cross-platform serialization scheme based on a subset of JS literal syntax. This being the case, it can only store certain things. Per http://www.json.org/ :
Objects: An object is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace). Each name is followed by : (colon) and the name/value pairs are separated by , (comma).
Arrays: An array is an ordered collection of values. An array begins with [ (left bracket) and ends with ] (right bracket). Values are separated by , (comma).
values: A value can be a string in double quotes, or a number, or true or false or null, or an object or an array. These structures can be nested.
Functions cannot be serialized into JSON because another non-JS platform would not be able to unserialize and use it. Consider the example in reverse. Say I had a PHP object at my server which contained properties and methods. If I serialized that object with PHP's json_encode() and methods were included in the output, how would my JavaScript ever be able to parse and understand PHP code in the methods, let alone use those methods?
What you are seeing in your resulting JSON is the toString() value of the function on the platform you're using. The JSON serilizer calls toString() on anything being serialized which isn't proper for JSON.
I believe your solution is to stop storing instances in JSON/local storage. Rather, save pertinent data for an instance which you set back to a new instance when you need.
I know this question is answered already, however I stumbled upon this by accident and wanted to share a solution to this problem, if anyone is interested.
instead of doing this:
var item = window.localStorage.getItem("itemKey");
item = JSON.parse(item);
item.save();
do something like this:
// get serialized JSON
var itemData = window.localStorage.getItem("itemKey");
//instantiate new Item object
var item = new Item();
// extend item with data
$.extend(item, JSON.parse(itemData));
// this should now work
item.save();
this will work so long as the function you are wanting to call (ie, save()) is prototypal and not an instance method (often times the case, and is indeed the case in the OP's original question.
the $.extend method is a utility method of jquery, but it is trivial to roll your own.
You cant do that, how can javascript possibly knows that item have a save function ? json doesnt allow functions as datas. just read the json spec , you cant save functions.
what you need to do is to create a serialize and deserialize method in the hash you want to stock. that will specifiy what to export and how you can "wake up" an object after parsing the corresponding json string.
You can only store plain Objects in DOMstorages (cookies, urlparams..., everything that needs [de]serialisation through JSON.stringify/JSON.parse). So what you did when sending the ajax data
ajaxsend(this.data);
also applies to string serialisation. You can only store the data, not the instance attributes (like prototype, constructor etc.). So use
savestring(JSON.stringify(item.data));
which is possible because item.data is such a plain Object. And when restoring it, you will only get that plain data Object back. In your case it's easy to reconstruct a Item instance from plain data, because your Items hold their values (only) in a public available property:
var item = new Item;
item.data = JSON.parse(getjsonstring());
Disclaimer
Not a full time time J.S. Developer, answer may have some minor bugs:
Long Boring Explanation
As mentioned by #JAAulde, your object cannot be serialized into JSON, because has functions, the technique that you are using doesn't allow it.
Many people forget or ignore that the objects that are used in an application, may not be exactly the same as saved / restored from storage.
Short & quick Answer
Since you already encapsulate the data members of your object into a single field,
you may want to try something like this:
// create J.S. object from prototype
Item item = new Item();
// assign values as you app. logic requires
item.data.name = "John Doe";
item.data.description = "Cool developer, office ladies, love him";
// encoded item into a JSON style string, not stored yet
var encodedItem = JSON.stringify(item.data)
// store string as a JSON string
window.localStorage.setItem("itemKey", encodedItem);
// do several stuff
// recover item from storage as JSON encoded string
var encodedItem = window.localStorage.getItem("itemKey");
// transform into J.S. object
item.data = JSON.parse(encodedItem);
// do other stuff
Cheers.