Vuetify Data-Table Header array not accepting empty child associations - javascript

I have a data-table using Vuetify that passes a localAuthority prop from a rails backend. It all works really well until I pass an empty child association (nested attribute). In this case 'county':
<script>
import axios from "axios";
export default {
name: 'LocalAuthorityIndex',
props: {
localAuthorities: {type: Array, default: () => []},
counties: {type: Array, default: () => []},
localAuthorityTypes: {type: Array, default: () => []}
},
data() {
return{
search: '',
dialog: false,
testmh: 'hello',
dialogDelete: false,
headers: [
{ text: 'Name', align: 'start', value: 'name' },
{ text: 'ONS Code', value: 'ons_code' },
{ text: 'ID', value: 'id' },
{ text: 'Population', value: 'population' },
{ text: 'county', value: 'county.name' },
{ text: 'Website', value: 'website' },
{ text: 'Actions', value: 'actions', sortable: false },
],
So in the example above it works as long as all records have a county association (belongs_to). However, if one record does not have a 'county' associated with it then I get the following error:
[Vue warn]: Error in render: "TypeError: Cannot read properties of undefined (reading 'name')"
I have tried lots of things like adding in a conditional statement like below:
{ text: 'county', value: ('county.name' ? 'county.name' : nil )},
But nothing seems to work.

According to your <v-data-table> code at Codepen, I see that you are overriding default table item slots with your own.
Your error are from this part of code:
...
<template #item.county.name="{ item }">
<a :href="'/counties/' + item.county_id">
{{ item.county.name }}
</a>
</template>
...
Take a look at first string. #item.county.name is a short form of v-slot:item.county.name and comes from one of your strings in headers array:
...
{ text: 'county', value: 'county.name' },
So there's no error, this part are correctly parsed by vuetify library even when your item will not contain any county.
The error is in 3rd string of the above code. You are trying to print name of county without checking its existence. That's why you are getting ...Cannot read properties of undefined... error.
I guess you may fix your issue this way:
<template #item.county.name="{ item }">
<a :href="'/counties/' + item.county_id">
{{ item.county ? item.county.name : 'No name' }}
</a>
</template>
Of course, if you need to hide your link to counties in this case, you may also add v-if (or v-show) into a tag.
I also created a small Codepen with some static data. Take a look into item.name.text slot in this playground, maybe it will help you to understand similar object associations.

Related

how to render a specific field dynamically in Material Table React

HI I am using Material Table of React, what I want to do is generate a label tag for every cell, what I did is:
<Table
onChangePage={handleChangePage}
page={props.currentPage}
totalCount={props.totalCount}
options={{
paging:true,
pageSizeOptions:[10, 15, 25, 50],
pageSize: props.rowsPerPage,
padding: "dense",
search: false,
toolbar:false
}}
columns={columns.map((tableColumn) =>{
return{
...tableColumn,
render: (rowData:VulnerabilityData) =>
(<label>
{rowData[tableColumn.field]}. <---- error 'undefined'
</label>)
}
})}
data={vulnerabilityDataAct}
/>
In order to get the specific field, I passed in the tableColumn.field in the render,
but I got the error
TS2538: Type 'undefined' cannot be used as an index type.
I think tableColumn.field is not allowed here, so how do I dynamically pass the tableColumn field and used as an index to render the value???
Edit:
columns variables in above code:
const columns: TableColumn<VulnerabilityData>[] = [
{
title: 'Due Date',
field: 'remediation_due_date',
},
{
title: 'Application',
field: 'primaryApplication'
},
{
title: 'Impact',
field: 'consequence'
},
{
title: 'Mitigation',
field: 'solution'
},
{
title: 'CVE Description',
field: 'cve_urls'
},
{
title: 'Vulnerability Fix',
field: 'vendor_urls'
}
// and other 100 columns
];
and the definition of VulnerabilityData
export interface VulnerabilityData {
primaryApplication: string;
networkEnvironment: string;
remediation_due_date: string,
// ... other fields
}
The First thing is that you don't have to specify index numbers in the custom column rendering. In custom column rendering Material table provides single rowData for that specific talbe field. This means you're not required to specify index number Just use the rowData.FieldName. You can do it as follows
columns={[
{ title: "Any Title", render: rowData => rowData.FieldYouWantToDisplay },
]}
Taking a shot at this. It looks like the error you are seeing here may be a typescript compiler error.
See this post: Type 'undefined' cannot be used as index type
If it is a compiler error, you may fix it by explicitly defining the type of tableColumns in your map function. This type could be {field: string}, in order to let the typescript compiler know that tableColumn.Field will not be undefined.
You could also tackle this by setting a type on columns field before it is mapped.
Or you could also use rowData[tableColumns.field!], as in the SO link.
I hope this solves your problem!

kendo angular menu without typescript

How I can use the kendo menu without typescript?
html
<kendo-menu [items]="menuItems" [vertical]="true" style="display:inline-block;" (select)="onMenuSelected($event)"></kendo-menu>
TS
menuItems: any[] = [
// {
// text: "Rename",
// },
{
text: "Delete",
},
{
text: "Copy",
},
];
I want to use only html to use of menu
Technically, you can enter the data in the template itself, like this:
<kendo-menu [items]="
[{
text: 'Rename'
},
{
text: 'Delete'
},
{
text: 'Copy'
}]">
</kendo-menu>
Now, while it is possible, it's not good practice. Even if the menu, in this case, is static and simple, it's better to have a const on the component containing the menu entries, or perhaps in a dedicated file if you have many such constants which you in several places.

Vuejs2: how to judge props update when using object as a prop?

Suppose I have an array feedsArray, the example value may look like this:
this.feedsArray = [
{
id: 1,
type: 'Comment',
value: 'How are you today ?'
},
{
id: 2,
type: 'Meet',
name: 'Daily sync up'
}
]
Suppose I have registered two components: Comment and Meet, Each component has a prop setting as the following:
props: {
feed: Object
}
and the main component has the following definition:
<component v-for="feed in feedsArray" :feed="feed" :key="feed.id" :is="feed.type"></component>
As you can see, it uses is property to select different component. My question is, how to detect feed object change in the child component ? Like when I set
this.feedsArray[0] = {
id: 1,
type: 'Comment',
value: 'I am not ok'
}
How can the Comment component detect the changes ? I tried to add a watcher definition in the child component like the following:
watch: {
feed: {
handler (val) {
console.log('this feed is changed')
},
deep: true
}
},
But it doesn't work here. Anyone know how to solve this ?
Do not assign directly to an array using index - use splice() instead, otherwise JavaScript can not detect that you have changed the array.
If you want to change only the value of an already existing key of an object - then simply update it e.g. this.feeds[0].value = 'I am not okay any more';
This works for existing keys only - otherwise you have to use this.$set(this.feeds[0], 'value', 'I am not okay any more');

React won't pass a particular value to "props"

I'm having a strange issue that I can't pin down with React (I'm using CoffeeScript as well, but I highly doubt this is a factor). Basically, I'm following along with a tutorial in which a message feed is built using a Feed component (the parent), FeedList component (child), and a FeedItem (grandchild)...sorry if my terminology is incorrect. The relevant code is:
Feed.cjsx
getInitialState: ->
FEED_ITEMS = [
{ key: 1, title: 'Realtime data!', description: 'Firebase is cool', voteCount: 49 }
{ key: 2, title: 'JavaScript is fun', description: 'Lexical scoping FTW', voteCount: 34 }
{ key: 3, title: 'Coffee makes you awake', description: 'Drink responsibly', voteCount: 15 }
]
{
items: FEED_ITEMS
formDisplayed: false
}
...
render: ->
...
<FeedList items={#state.items} onVote={#onVote} />
FeedList.cjsx
render: ->
feedItems = #props.items.map ((item) ->
<FeedItem key={item.key} ... />
).bind(#)
<ul className='list-group container'>
{feedItems}
</ul>
FeedItem.cjsx
render: ->
<li key={#props.key} className='list-group-item'>
...
</li>
If I console.log "#props.key" in the render method for FeedItem, I get undefined. But if I log "item.key" from inside the map function of FeedList's render method, I get 1, 2, 3, as I should. So it seems to me that, for whatever reason, React doesn't want to pass the "key" prop to the FeedItem. Any thoughts?
For anyone else stumbling across this, react only has a few reserved props but they are worth noting. key, ref, __self and __source.
var RESERVED_PROPS = {
key: true,
ref: true,
__self: true,
__source: true
};
^^ Taken from the react source.
Also worth noting __self={this} is really useful if you're receiving invariant violation errors and would like to be able to debug them down to a component level.
Since react treats key as a special attribute (http://facebook.github.io/react/docs/special-non-dom-attributes.html), it cannot be accessed via the props. The react documentation also warns against setting keys within plain html tags (http://facebook.github.io/react/docs/multiple-components.html#dynamic-children), and suggests wrapping multiple components in a react component.
If you rename key to something non-reserved, it should work:
Feed.cjsx:
FEED_ITEMS = [
{ itemId: 1, title: 'Realtime data!', description: 'Firebase is cool', voteCount: 49 }
{ itemId: 2, title: 'JavaScript is fun', description: 'Lexical scoping FTW', voteCount: 34 }
{ itemId: 3, title: 'Coffee makes you awake', description: 'Drink responsibly', voteCount: 15 }
]
then you can access the itemId via #props.itemId in the child component (FeedList).
FeedList:
feedItems = #props.items.map ((item) ->
<FeedItem key={item.itemId} ... />
).bind(#)
Note that the keys for each component need to be unique for each component, or node in the DOM, which is why it makes sense that keys cannot be inherited, as setting both parent and child to the same key would not allow react to identify them as separate entities when rendering the DOM.

UI-bootstrap: Cannot read property 'remove' of null

I'm using ui-bootstrap(accordion) for angular.
Also im creating recursive templates with directives to display nested object structure smthng like this:
[
{
name: String("Name1"),
key: String("name1"),
value: String("some text")
},
{
name: String("Name2"),
key: String("name2"),
value: {[
{
name: String("Object1"),
key: String("object1"),
value: {[
{
name: String("Object1 Name3"),
key: String("object1.name3"),
value: Object()
},
]}
},
{
name: String("Name4"),
key: String("name4"),
value: String()
},
]}
},
{
name: String("Name5"),
key: String("name5"),
value: Number("44")
}
]
To make displaying of complex object structure possible I used directive with recursive template and its works fine.
Also I have two buttons: "Edit" - makes possible edit values and "Cancel" - turns all input fields to disable mode.
When I'm pressing "Cancel" button I got this exception:
TypeError: Cannot read property 'remove' of null
at onDestroyTooltip (http://localhost:8080/js/lib/angularjs/ui-bootstrap-tpls-0.5.0.js?8b58789:2248:20)
at Scope.$broadcast (http://localhost:8080/js/lib/angularjs/angular.js?8b58789:12691:28)
at Scope.$destroy (http://localhost:8080/js/lib/angularjs/angular.js?8b58789:12349:14)
at HTMLDivElement.<anonymous> (http://localhost:8080/js/lib/angularjs/angular.js?8b58789:1017:18)
at HTMLDivElement.jQuery.event.dispatch (http://localhost:8080/js/lib/jquery/jquery.js?8b58789:3332:58)
at HTMLDivElement.elemData.handle.eventHandle (http://localhost:8080/js/lib/jquery/jquery.js?8b58789:2941:81)
at Object.jQuery.event.trigger (http://localhost:8080/js/lib/jquery/jquery.js?8b58789:3210:40)
at jQuery.fn.extend.triggerHandler (http://localhost:8080/js/lib/jquery/jquery.js?8b58789:3874:45)
at removePatch [as remove] (http://localhost:8080/js/lib/angularjs/angular.js?8b58789:2213:21)
at Object.leave (http://localhost:8080/js/lib/angularjs/angular.js?8b58789:4143:17)
Line: onDestroyTooltip (http://localhost:8080/js/lib/angularjs/ui-bootstrap-tpls-0.5.0.js?8b58789:2248:20) in stacktrace points to this part of ui-bootsrap code:
scope.$on('$destroy', function onDestroyTooltip() {
$timeout.cancel( transitionTimeout );
$timeout.cancel( popupTimeout );
unregisterTriggers();
tooltip.remove(); // <-- ERROR here!!!!!!!!!!!!!
tooltip.unbind();
tooltip = null;
});
Can some one explain me what went wrong? Why im getting this exception and how I can prevent it?

Categories