How to extract data from nested object with pug - express

I'm trying to access data from nested JSON object without any javascript in PUG and product.highlights[0].heading , the index needs to looped.
JSON FORMAT
[{"id":"0.33454785604755677","title":"Product 2 Title",
"highlights":[
- {"heading":"Product 2 Heading 1","description":"Product 2 Description 1"},
- {"heading":"","description":""},
- {"heading":"","description":""},
- {"heading":"","description":""}]
}]
I tried
-var x = [0,1,2,3,4,5]
-var high =[product.highlights[0].heading,product.highlights[1].heading,product.highlights[2].heading,product.highlights[3].heading]
each val in x
-var p = high[x] // here its not considering 'x'
h3 #{p}
and directly using loop too
each i in [0,1,2,3,4,5]
h3 #{product.highlights[i].heading} //but here its not considering 'i'
Its working inside 'name' , 'for' .
but i need it to work inside:
- value=(editing ? product.highlights[0].heading:'')
each i in [1, 2, 3, 4, 5, 6]
.form-control
label(for="highlights[" + i +"][heading]") Highlights Number #{i} Heading
input(type="text",name="highlights[" + i +"][heading]",value=(editing ? product.highlights[0].heading:''))
I don't know how to access it through javascript in pug
Can someone tell me how can i do that?

-function productHeading(product,y){return product.highlights[y].heading;}
each i in [0, 1, 2, 3, 4, 5]
.form-control
label(for="highlights[" + i +"][heading]") Highlights Number #{i+1} Heading
input(type="text",name="highlights[" + i +"][heading]",value=(editing ? productHeading(product,i):''))
product stores the object found by findById method which later sent to the pug file
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const SubProductSchema = new Schema({
product_id: Schema.Types.ObjectId,
title: String,
name:{
type: String,
unique: true,
required: true
},
price:Number,
image:String,
alt: String,
quantity:Number,
description:String,
bgImage:String,
primaryImage:String,
primaryAlt: String,
primaryHeading:String,
primaryDescription:String,
highlights:[{
heading:String,
description:String,
icon:String
}],
specs:[{
heading:String,
description:String,
image:String
}],
featured:Boolean,
preOrder:Boolean,
video:Boolean
});
module.exports = mongoose.model('xxx',xxx);
Controller File
const Product = require('../models/product');
.
.
Product.findById(prodId)
.then( product => { ....
And so on .
Editing is a boolean variable , if its true the productHeading function in pug file is called and value is initalized to it else its set to '' (empty)

Related

React Native can not using Spread Operator to update object in array

i have the state that control the flatList data
const [data, setData] = useState([])
i have a object like below(after get from network, it's show success in FlatList)
data = [{
'name' : 1,
},
{'name' : 2,
}]
Now i want to update first object {'name': 1} by add some key/value like this:
{ 'name' : 1, 'text' : 'this is text'}
Here is my code:
const mathched = data[0]
mathched = [
...mathched,
{'text': 'this is text'}
]
But i got error: TypeError: "mathched" is read-only
I tried other solution by set new key to object:
const newData = [...data]
const mathched = newData[0]
mathched['text'] = 'this is text'
setData(newData)
But data not changed
Can someone guide me how to use Speard Operator to done my solution? Thanks
The problem is that the state value is a read-only variable that can be modified only via the setter, setData in this case.
When you do const matched = data[0] then matched = newData[0] you are attempting to store the new value without the setter usage.
One way to go would be:
// Usign for example Lodash clone
const newClonedData = clone(data);
newClonedData[0] = { ...matched[0], {'text': 'this is text'} };
setData[newClonedData];

getting ReferenceError: testData is not defined when using webdriverio Dataprovider

I am getting the following error when I am trying to use a feature webdriverio comes with for dataprovider:
I have put the following in the wdio.conf.js:
dataProviders: ['./test/dataproviders/dataObject.js'],
and created dataObject.js as the following:
const dataObject = [
{
a: 0,
b: 1,
expected: 1,
description: 'returns 1 when 0 is added 1',
},
{
a: 1,
b: 2,
expected: 3,
description: 'returns 3 when 1 is added 2',
}
];
dataProvider("../specs/smoke/add.spec.js", dataObject);
and in add.spec.js, I have:
describe(verify addition - ${testData.description}, () => {
...
can you tell me what might have been wrong? will I have to import testData from somewhere? but I have read from the following file that testData is a global variable:
https://github.com/webdriverio/webdriverio/pull/4452/files#diff-65fd20fda801d80cbe511bf165b5adac8e324d3897f6bc7090aa13c943eebf8bR76
Can you please help?
[0-0] (node:54912) UnhandledPromiseRejectionWarning: ReferenceError: testData is not defined

Ramda - extract object from array

I am trying to filter an array of objects with Ramda and it is working almost as I planned but I have one small issue. My result is array with one filtered object which is great but I need only object itself not array around it.
My example data set:
const principlesArray = [
{
id: 1,
harvesterId: "1",
title: "Principle1"
},
{
id: 2,
harvesterId: "2",
title: "Principle2"
},
]
And that is my Ramda query:
R.filter(R.propEq('harvesterId', '1'))(principlesArray)
As a result I get array with one filtered element but I need object itself:
[{"id":1,"harvesterId":"1","title":"Principle1"}]
Any help will be appreciated
You can use R.find instead of R.filter, to get the first object found:
const principlesArray = [{"id":1,"harvesterId":"1","title":"Principle1"},{"id":2,"harvesterId":"2","title":"Principle2"}]
const result = R.find(R.propEq('harvesterId', '1'))(principlesArray)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
A more generic approach would be to create a function that takes a predicate used by R.where, pass the partially applied R.where to R.find, and then get the results by applying the function to the array:
const { pipe, where, find, equals } = R
const fn = pipe(where, find)
const principlesArray = [{"id":1,"harvesterId":"1","title":"Principle1"},{"id":2,"harvesterId":"2","title":"Principle2"}]
const result = fn({ harvesterId: equals('1') })(principlesArray)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>

Use Ramda.js to pull off items from object

This question is about how to perform a task using RamdaJS.
First, assume I have an object with this structure:
let myObj = {
allItems: [
{
name: 'firstthing',
args: [
{
name: 'arg0'
},
{
name: 'arg1'
}
],
type: {
name: 'type_name_1'
}
},
{
name: 'otherthing',
args: [
{
name: 'arg0'
}
]
}
]
}
I am trying to create an object that looks like:
{
arg0: 'arg0', // myObj.allItems[0].args[0].name
typeName: 'type_name_1' // myObj.allItems[0].type.name
}
(I know the names are stupid, arg0, typeName. It's not important)
So if we weren't using Ramda, this is how I'd do it imperatively:
// The thing I'm searching for in the array (allItems)
let myName = 'firstthing';
// Here's how I'd find it in the array
let myMatch = myObj.allItems.find(item => item.name === myName);
// Here is the desired result, by manually using dot
// notation to access properties on the object (non-functional)
let myResult = {
arg0: myMatch.args[0].name,
typeName: myMatch.type.name
};
// Yields: {"arg0":"arg0","typeName":"type_name_1"}
console.log(myResult)
Finally, just for good measure, this is as far as I've gotten so far. Note that, I'd really like to accomplish this in a single compose/pipe.
(An object goes in, and an object with the desired data comes out)
const ramdaResult = R.compose(
R.path(['type', 'name']),
R.find(
R.propEq('name', myName)
)
)(R.prop('allItems', myObj))
Thanks
A combination of applySpec and path should work:
const transform = applySpec ({
arg0: path (['allItems', 0, 'args', 0, 'name']),
typeName: path (['allItems', 0, 'type', 'name'])
})
const myObj = {allItems: [{name: 'firstthing', args: [{name: 'arg0'}, {name: 'arg1'}], type: {name: 'type_name_1'}}, {name: 'otherthing', args: [{name: 'arg0'}]}]}
console .log (
transform (myObj)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {applySpec, path} = R </script>
But depending upon your preferences, a helper function might be useful to make a slightly simpler API:
const splitPath = useWith (path, [split('.'), identity] )
// or splitPath = curry ( (str, obj) => path (split ('.') (str), obj))
const transform = applySpec({
arg0: splitPath('allItems.0.args.0.name'),
typeName: splitPath('allItems.0.type.name'),
})
const myObj = {allItems: [{name: 'firstthing', args: [{name: 'arg0'}, {name: 'arg1'}], type: {name: 'type_name_1'}}, {name: 'otherthing', args: [{name: 'arg0'}]}]}
console .log (
transform (myObj)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {applySpec, path, useWith, split, identity} = R </script>
splitPath is not appropriate for Ramda, but it's a useful function I often include, especially if the paths are coming from a source outside my control.
Update
Yes, I did miss that requirement. Serves me right for looking only at the input and the requested output. There's always multiple incompatible algorithms that give the same result for a specific input. So here's my mea culpa, an attempt to break this into several reusable functions.
Lenses are probably your best bet for this. Ramda has a generic lens function, and specific ones for an object property (lensProp), for an array index(lensIndex), and for a deeper path(lensPath), but it does not include one to find a matching value in an array by id. It's not hard to make our own, though.
A lens is made by passing two functions to lens: a getter which takes the object and returns the corresponding value, and a setter which takes the new value and the object and returns an updated version of the object.
An important fact about lenses is that they compose, although for technical reasons the order in which you supply them feels opposite to what you might expect.
Here we write lensMatch which find or sets the value in the array where the value at a given path matches the supplied value. And we write applyLensSpec, which acts like applySpec but takes lenses in place of vanilla functions.
Using any lens, we have the view, set, and over functions which, respectively, get, set, and update the value. Here we only need view, so we could theoretically make a simpler version of lensMatch, but this could be a useful reusable function, so I keep it complete.
const lensMatch = (path) => (key) =>
lens
( find ( pathEq (path, key) )
, ( val
, arr
, idx = findIndex (pathEq (path, key), arr)
) =>
update (idx > -1 ? idx : length (arr), val, arr)
)
const applyLensSpec = (spec) => (obj) =>
map (lens => view (lens, obj), spec)
const lensName = (name) => lensMatch (['name']) (name)
const transform = (
name,
nameLens = compose(lensProp('allItems'), lensName(name))
) => applyLensSpec({
arg0: compose (nameLens, lensPath (['args', 0, 'name']) ),
typeName: compose (nameLens, lensPath (['type', 'name']) )
})
const myObj = {allItems: [{name: 'firstthing', args: [{name: 'arg0'}, {name: 'arg1'}], type: {name: 'type_name_1'}}, {name: 'otherthing', args: [{name: 'arg0'}]}]}
console .log (
transform ('firstthing') (myObj)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {lens, find, pathEq, findIndex, update, length, map, view, compose, lensProp, lensPath} = R </script>
While this may feel like more work than some other solutions, the main function, transform is pretty simple, and it's obvious how to extend it with additional behavior. And lensMatch and applyLensSpec are genuinely useful.

Delete and add attributes with array.map and the spread operator

I'm trying to mangle data returned from an api. I've got an array of objects returned. I want to delete the password field and then add a couple of additional fields. I'd like to use the spread operator but my process feels a bit clunky.
myArray.map( item => {
const newItem = { ...item };
delete newItem.password;
newItem.saved = true;
return newItem;
});
Is there a nicer way to do this?
Given an array of objects -
const myArrayOfObjects = [
{id: 1, keyToDelete: 'nonsense'},
{id: 2, keyToDelete: 'rubbish'}
];
Delete the attribute keyToDelete, and add a new key newKey with the value "someVar".
myArrayOfObjects.map(({ keyToDelete, ...item}) => { ...item, newKey:'someVar'});
Updating the array to
[
{id: 1, newKey:'someVar'},
{id: 2, newKey:'someVar'}
]
See this great post for more information on the deletion method.