angular 5: setting (click) value from an object not working - javascript

I have a nav menu that is rendered using a navigation.ts json file for the menu items. When it gets to the navitem component it uses a ngIf to check if the item from the navigation file has a "function" key and if it does, the desired behavior is for it to use the string value from item.function in the object to fill the value for the (click) event.
In reality, the console throws an error saying "_co.item.function is not a function"
HTML
<span class="nav-link" *ngIf="item.function" (click)="item.function()" matRipple>
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
{{item.badge.title}}
</span>
</span>
Navigation.ts
[{
"id": "accounting",
"title": "Accounting",
"type": "collapse",
"children": [
{
"id" : "salesmenSalesLocation",
"title": "Salesmen Sales Location",
"type": "item",
"function": "handleSelect(ReportTypes.SalesmenSalesLocations)"
},
{
"id": "laggingLedgerEntries",
"title": "Lagging Ledger Entries",
"type": "item",
"function": "handleSelect(ReportTypes.LaggingLedgerEntries)"
}
]}]
I have also tried it as (click)="item.function" with no success.

I'm assuming you can change the data source here, because otherwise I don't see any good solution.
A string is not a function, and while you can turn it into one with eval that is a bad idea. What you should really do instead is just pass in a value that tells the function what to use.
Change your data to something like this:
{
"id" : "salesmenSalesLocation",
"title": "Salesmen Sales Location",
"type": "item",
"reportTypeSource": "SalesmenSalesLocations"
},
{
"id": "laggingLedgerEntries",
"title": "Lagging Ledger Entries",
"type": "item",
"reportTypeSource": "LaggingLedgerEntries"
}
Then pass that value to your function and use that to tell it where to look:
handleSelect (reportTypeSource: string) {
const reportType = ReportTypes[reportTypeSource]
// continue as before
}
And call it in your HTML like this:
(click)="handleSelect(item.reportTypeSource)"

Problem lies here:
"function": "handleSelect(ReportTypes.LaggingLedgerEntries)"
And here:
(click)="item.function()"
You cannot simply pass a string and expect the component to execute a function and also know exactly what to do. Here you need to pass the actual function.
Your setup looks over-config'd. I would tear the config down and put the logic into the component itself. Don't be afraid to have more template as well, if anything it makes things more legible (as opposed to the config)

Does that function exist in the component or just the model? If it is just on the model it won't work. (click) is looking for a method on the component. It is, ostensibly just a string in this instance.

Related

Blank screen in vue.js if not using created() life cycle hook or spread operator (...)

The following example gives me a blank screen (jsfiddle here). Even the parts which have nothing to do with the loop are not being rendered.
HTML:
<div id="app">
<button #click="objectFromApi">
run objectFromApi function
</button>
<div
v-for="obj in myObject[0].results"
:key="obj.id"
>
<p>
{{ obj.message }}
</p>
</div>
</div>
JavaScript:
new Vue({
el: "#app",
data: {
myObject: []
},
methods: {
objectFromApi: function(){
this.myObject.push(
{
"count": 5,
"results": [
{
"id": 1,
"message": "object 1"
},
{
"id": 2,
"message": "object 2"
}
]
}
)
}
},
//created() {
// this.objectFromApi()
//}
})
Nevertheless it does work if:
1.) Either using objectFromApi function directly in the created life cycle hook (what I don't want!)
created() {
this.objectFromApi()
}
2.) Or (without the use of created life cycle hook) if I go directly into the nested results array and spread the objects out like this (what I also don't want!)
this.myObject.push(
...{
"count": 5,
"next": "http://127.0.0.1:8000/api/someurl/?page=2",
"previous": null,
"results": [
{
"id": 1,
"message": "object 1"
},
{
"id": 2,
"message": "object 2"
}
]
}.results
)
When using option 2.) of course the v-for loop has to look different:
v-for="obj in myObject" instead of v-for="obj in myObject[0].results"
What is wrong with my initial example?
When the component is first rendering the array myObject will be empty.
During rendering it attempts this:
<div
v-for="obj in myObject[0].results"
:key="obj.id"
>
The value of myObject[0] will be undefined. Attempting to access the results property of undefined will result in an error. This error will cause rendering to fail. Nothing will be shown, even the parts that didn't fail.
There are various ways to fix this problem. You could prepopulate the data with suitable empty properties:
data: {
myObject: [
{
results: []
}
]
}
Alternatively, as you've noted, you could change the loop to use v-for="obj in myObject", changing objectFromApi accordingly to only store the results array in myObject. Even if you don't want that exact change some similar change is probably a good idea because the [0] part strongly suggests you've got a problem with your data model. The key thing here is that it avoids trying to access nested objects that don't exist. The use of the spread operator in your second example is largely irrelevant.
Or you could skip the loop in the template:
<template v-if="myObject[0]">
<div
v-for="obj in myObject[0].results"
:key="obj.id"
>
...
</div>
</template>

searchkit: RefinementListFilter can't access certain data in json

I'm usig searchkit as part of a website, but have problems in accessing my data that's been converted into json format previously.
My json directory looks like this:
(...)
hits:
0:
_index: content
_type: content
_source:
meta:
author: content
(...)
json
and I'm using RefinementListFilter (in ReactDOM.render) and this works fine:
<RefinementListFilter id="index" title="Index" field={"_index"}/>
<RefinementListFilter id="Type" title="Type" field={"_type"}/>
whereas i can't seem to access the content that is written under author:
<RefinementListFilter id="Author" title="Author" field={"_source.meta.author"}/>
this doesn't work (no error, nothing happens when I type this), although when i use _source.meta.author in this context it works like expected:
class SearchHit extends React.Component {
render() {
const result = this.props.result;
return (
<div className={this.props.bemBlocks.item("author")}> <b> Index: </b> {result._index} </div>
<div className={this.props.bemBlocks.item("author")}> <b> Author: </b> {result._source.meta.author} </div>
)}}
What am I doing wrong? The first and last snippet work just fine, it's just the middle one that doesn't.
The problem is within the field indices of your elasticsearch instance.
According to the docs, Searchkit needs two different kinds of indexed fields for searching and filtering.
In your case it seems like the field author is not indexed correctly.
To solve this, you need to change the elasticsearch mapping for the field author:
...
"meta": {
"properties": {
"author": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
...
You can then access the authors in the Refinementfilter via
<RefinementListFilter id="author" title="Author" field={"meta.author.raw"}/>
Try to restructure your JSON file for distinct clarification. You need two different fields for searching and filtering.
"meta": {
"properties": {
"author": {
"type": "text",
"fields": {
"val": {
"type": "keyword"
}
}
While in a Refinementfilter, it can be accessed this way
<RefinementListFilter id="Author" title="Author" field={"meta.author.val"}/>

Error getting a single value from a collection

I have a collection called notification and i am trying to get a single value with findOne()
var allnotices = Notifications.findOne({eventownernumber:"2"},{sort: {noticedate: -1, limit: 1}}).noticemessage;
I want to get the value where the eventownernumber is 2 and i want to get the latest record and i only want one record.
Even though noticemessage is part of the row fields,i get the error that noticemessage is undefined.
This is the schema
{
"_id": "tmkWCydSKZtYdrKTZ",
"eventoriginalid": "3bXvARk6K6yhee6Hi",
"lat": "-1.851881824302658",
"lng": "96.987469482421875",
"eventownernumber": "1",
"eventownernames": "Test 1",
"eventtitle": "ci",
"eventtime": "08:05",
"invited": "0",
"eventduration": "21",
"eventtype": "notification",
"eventcategory": "hackathon",
"eventstatus": "11",
"createdAt": {
"$date": "2016-11-02T12:38:40.378Z"
},
"noticedate": {
"$date": "2016-11-02T16:50:53.394Z"
},
"noticenumber": "2",
"noticenames": "Test 2",
"noticemessage": "Test 2 has joined your event ci",
"noticestatus": "12"
}
Why is noticemessage undefined?.
There are four basic possibilities why Collection.findOne(query).key could yield an error:
There is no document matching the query therefore you're trying to reference undefined.key
The key in question doesn't exist in the returned document
The document exists in the database but isn't being published by the server and being subscribed to by the client
The document exists and is published and subscribed to but the subscription is not yet .ready(), i.e. you need to wait before you can access it.
A common defensive pattern is:
const oneDoc = myCollection.findOne(query);
let myVar = oneDoc && oneDoc.key;
if ( myVar ) {
// do the thing
} else {
// handle the error
}
You need to save the number as integer for eventownernnumber (and please write it like eventOwnerNumber, which is a good practice for readability), not string. Either use input type="number" or convert the value to integer like this:
Number(valueHere);
The rest of your query looks fine to me but you don't need limit since you do findOne() and you find the newest inserted doc with noticedate: -1
Another thing is, you need to save the date like this in your insert():
noticeDate: new Date() //your current query should give you the right document after this change

how to fetch json data in scope variable angularjs

Here is my Json data
"data": {
"address": {
"postalCode": "112629",
"state": "DL",
"city": "new city",
"streetAddress": "my street"
},
"specialities": [
{
"_id": "577692f7",
"name": "Football",
"description": "game",
"__v": 0
}
]
}
$scope.test = data;
i am fetching data in html by
ng-repeat="mytest in test" than
mytest.address.city // this is working fine
mytest.specialities.name // not printing anything
i am facing the problem in accessing the specialities name i think that is because of specialities is a array but don't know how to get it.
You defined a specialities object with only one array inside
try
mytest.specialities[0].name
Update:
Also you may want to make sure that the array has at least one element, otherwise you mayget a TypeError: Cannot read property 'name' of undefined.
So the code sould look like this:
mytest.specialities.length > 0 ? mytest.specialities[0].name : '(some default value)';
Assuming there will be many specialities you should use ng-repeat to display them all.
<p ng-repeat="s in mytest.specialities"> {{s.name}} / {{s._id}} / {{s.description}} </p>
Yes mytest.specialities is array. JSON has two possible options [ ] - array, { } - object. In this situation we have array of objects - [ { /* object data */ } ] so to get object parameter first go to array element like this ( example getting first element on index 0 ):
mytest.specialities[0].name
second element:
mytest.specialities[1].name
example each:
<div ng-repeat="special in mytest.specialities">
<span>{{special.name}}</span>
</div>
of course before that set mytest to scope like:
$scope.mytest=mytest;//mytest is your data structure

Iteration in handlebar using backbone

I'm using backbone and handlebars for templating and i'm new to this.
My current json is in the below format and the code works fine.
[
{
"id": "10",
"info": {
"name": "data10"
}
},
{
"id": "11",
"info": {
"name": "data11"
}
}
]
But when i change my json structure to something like shown below i'm having difficulty in getting things to be populated.
{
"total_count": "10",
"dataElements": [
{
"id": "10",
"info": {
"name": "data10"
}
},
{
"id": "11",
"info": {
"name": "data11"
}
}
]
}
How can i populate name, info and total_count keeping the current code structure ?
JSFiddle : http://jsfiddle.net/KTj2K/1/
Any help really appriciated.
A few things that you need to do in order for this to work.
Replace Backbone's core 'reset' on your collection with a custom one that understands the data you are passing to it. For example:
reset: function (data) {
this.totalCount = data.total_count;
Backbone.Collection.prototype.reset.call(this, data.dataElements);
}
Now when you reset your collection, it will pull the total_count out of the object you are resetting it with, and use Backbone's core reset with the dataElement array. Keep in mind you may have to do a similar thing with 'parse' if you're intending on pulling this from the server.
I'd recommend that (if your example looks anything like the real code you're working with) you reset your collection before getting to rendering.
var dataCollectionList = new dataCollection();
dataCollectionList.reset(jsonData);
var App = new AppView({model : dataCollectionList});
Now in your view's "render" method you can grab the 'totalCount' property off the collection -
render : function() {
//Should spit the total count into the element, just as an example
this.$el.append(this.model.totalCount);
//or console.log it
console.log(this.model.totalCount);
return this;
}
Voila. Side note - as someone who works with Backbone a lot, it drives me nuts when people set an attribute of something like "model" (i.e. peopleModel, itemModel, etc) and it ends up being a backbone collection. It's much clearer to name it after what it is - though some MVC purists may disagree a bit.
Also, in this code block:
_.each(this.model.models, function (myData) {
$(this.el).append(new ItemView({model:myData}).render().el);
}, this);
You don't need to do _.each(this.model.models.......). Since you're working with a collection, the collection has a built in 'each' method.
this.model.each(function (myData) { ..... } , this);
Quite a bit cleaner.

Categories

Resources