I use a v-for loop to list buttons for each category in my array. A function is called on click but it returns an error:
TypeError: Cannot read property 'name' of undefined
Every button is properly displayed in HTML with its name.
v-for loop:
<button :class="{selected: category.exist === true}" v-for="category in categories" :key="category.id" v-on:click="pushFilter(); category.exist = !category.exist">{{ category.name }} {{ category.exist }}</button>
categories data:
export default {
data: function () {
return {
categories: [
{
name: 'name1',
exist: false,
},
{
name: 'name2',
exist: false,
},
],
Method:
methods: {
pushFilter() {
console.log(this.category.name);
},
}
pushFilter() references this.category, but the component has no category prop (at least none shown in question). You're probably trying to access the category iterator of v-for. You could just pass that in the template binding:
<button v-for="category in categories" v-on:click="pushFilter(category)">
And update your method to receive the category argument:
export default {
methods: {
pushFilter(category) {
console.log(category.name)
}
}
}
Related
I am new to react and I created I have a json like this:
const parent: [{name:will, kids['child1', 'child2']}
{name: 'kia' kids['child1']}
{name: 'jim', kids['child1', 'child2']}]
I am having trouble accessing the values with this json. I am trying to create a list with all the name values in of array so I can put it in a dropdown but I keep getting 'undefined' when i try to print the list in my console.log
Also when I click the name I want to create input boxes based of the length of the kids list of the name selected. So for instance if I click 'will' in the dropdown, two input boxes will form with 'child1' and 'child2' being in both input boxes. but if i click "kia", one input box will form that already has "child 1" in it. Any ideas? I have having a lot of trouble accessing the values.
this is my attempt so far:
import Dropdown from 'react-dropdown';
parent: [{name:will, kids['child1', 'child2']}
{name: 'kia' kids['child1']}
{name: 'jim', kids['child1, 'child2']}]
class AppEX extends React.Component {
constructor() {
super();
this.state = {
parentnamelist: []
parentname: null
}
}
render() {
namelist: []
this.state.parent.map((e, key) => {
namelist.push({value:e.name,label:e.name})
})
return (
<select name="select" onChange={this.namelist}>
{num.map(function(n) {
return (<option value={n} selected={this.state.selected === n}>{n}</option>);
})}
</select>
any ideas?
There are various problems here.
The parent list was not well formatted, is should look like this:
const parent = [
{ name: "will", kids: ["child1", "child2"] },
{ name: "kia", kids: ["child1"] },
{ name: "jim", kids: ["child1", "child2"] }
]
You are using map in your render method to push parent names into a new list called namelist but you have to use forEach. map transforms a list while forEach does something to each member.
const namelist = [];
this.state.parent.forEach(e => {
namelist.push({ value: e.name, label: e.name });
});
Now render return:
The onChange handler must be a function, since you want to track the selected parent, I guess you want to save it to your state:
handleParentChoice = e => {
e.persist();
this.setState({
parentname: e.target.value
});
};
Then
return (
<div>
<select name="select" onChange={this.handleParentChoice}>
{namelist.map(n => (
<option key={n.value} value={n.value}>{n.label}</option>
))}
</select>
<br />
{this.state.parentname && // Shows below stuff only if parentname is not null
this.state.parent
.find(p => p.name === this.state.parentname) // Find the parent based on the saved name, then map the kids into input tags
.kids.map(k => <input key={k} type="text" />)}
</div>
);
Also, when you map something, every child should have a key prop.
See the code working here
I have an array of object like that :
{ id: 33617,
datePublication: 1532266465,
dateUpdate: 1532266574,
headline: 'An headline title here',
images: [ [Object] ] },
{ id: 33614,
datePublication: 1532265771,
dateUpdate: 1532271769,
headline: 'another super headline article',
images: [ [Object], [Object], [Object], [Object], [Object] ] }
so i iterate that way on my vue js template :
<v-flex v-for="(ip, i) in ips" :key="i" xs12 sm6 >
<v-card>
<v-card-media
:src="ip.images[0].url"
height="200px"
/>
<v-card-title primary-title>
<div>
<h3 class="headline mb-0">{{ ip.headline }}</h3>
<div>Located two hours south of Sydney in the <br>Southern Highlands of New South Wales, ...</div>
</div>
</v-card-title>
<v-card-actions>
<v-btn flat color="orange">Share</v-btn>
<v-btn flat color="orange">Explore</v-btn>
</v-card-actions>
</v-card>
</v-flex>
And here is my associated script :
var api = "https://my api.org/news/fr-FR/2018-25-07";
export default {
data() {
return {};
},
layout: "no-live",
async asyncData({ app }) {
const ips = await app.$axios.$get(api);
console.log(ips);
return { ips };
}
};
Each object in the images array should return me an id and an url, so i want to take that url as a source in my image but i have this error : Cannot read property '0' of undefined
it seems i need to do another loop over the images array, is there a proper way to do that with vue JS ?
if you have any objects in ips that doesn't have images, you would get that error,
you can try to add a conditional to not have an error in rendering
<v-card-media
v-if="ip.images && ip.images[0]"
:src="ip.images[0].url"
height="200px"
/>
I usually add a <pre>{{ip}}</pre> in these cases to see what's going on.
Try put v-if="ip.images" on v-card-media component. You will assure the images are not empty and loaded.
I am new to the Meteor and React Framework, and
I am trying to incorporate 'search' in meteor, and using the package easysearch for it. I am getting an error. The exact wordings of the error are as follows:
match.js:40 Uncaught
errorClass {message: "Match error: Expected particular constructor", path: "", sanitizedError: errorClass, errorType: "Match.Error", stack: "Error: Match error: Expected particular constructo…5a95662d577f9e8a17248e5683161da2f8b114da:3779:14)"}
errorType: "Match.Error"
message: "Match error: Expected particular constructor"
path: ""
I really cannot understand why this error is occurring and how to solve this. I am writing my code below, so that the error can be found exactly.
search.html (the blaze template for the search)
<template name="search">
<div id="search-wrap">
<div>Search page!</div>
<div class="black searchbar">
{{> EasySearch.Input index=index attributes=inputAttributes }}
</div>
{{#EasySearch.IfInputEmpty index=index }}
<div class="padded examples black">For example "Company 1"</div>
{{else}}
{{#if resultsCount}}
<div class="padded count-results black">{{resultsCount}} results found.</div>
{{/if}}
{{/EasySearch.IfInputEmpty}}
{{#EasySearch.IfSearching index=index }}
<div>Searching</div>
{{/EasySearch.IfSearching}}
<ol class="leaderboard">
{{#EasySearch.Each index=index }}
{{> User}}
{{/EasySearch.Each}}
</ol>
{{#EasySearch.IfNoResults index=index }}
<div class="padded no-results black">No results found</div>
{{else}}
{{/EasySearch.IfNoResults}}
{{> EasySearch.Pagination index=index maxPages=10 }}
{{! > EasySearch.LoadMore index=index}}
{{#if showMore}}
{{> EasySearch.Input name="mini-index" index=index attributes=inputAttributes }}
<ul>
{{#EasySearch.Each name="mini-index" index=index}}
<li>{{name}}</li>
{{/EasySearch.Each}}
</ul>
{{/if}}
<!-- Easy Search -->
</div>
<!-- End search -->
--></template>
<template name="User">
<li class="user black {{selected}}" id="user-link">
<span class="name">{{name}}</span>
</li>
</template>
The index.js file (Creating an index on the Collection - companies)
import Companies from "./companies.js";
import { EasySearch } from 'meteor/easy:search';
import { Meteor } from 'meteor/meteor';
import { Mongo } from "meteor/mongo";
export const CompaniesIndex = new EasySearch.Index({
engine: new EasySearch.MongoDB({
sort: function() {
//return based on the latest additions, newest on top
return { createdAt: -1 };
},
//something easy search always asks for
selector: function(searchObject, options, aggregation) {
let selector = this.defaultConfiguration().selector(searchObject, options, aggregation),
//to sort with category.
categoryFilter = options.search.props.categoryFilter;
//search with a category, not really sure what it does, using the easysearch docs.
if(_.isString(categoryFilter) && !_.isEmpty(categoryFilter)) {
selector.category = categoryFilter;
}
return selector;
}
}),
//collection name
collection: Companies,
//fieldname to be searched on
fields: ['name'],
defaultSearchOptions: {
//limit the results size to be 10
limit: 10
},
permission: () => {
return true;
}
});
// export const CompaniesIndex;
The jsx file (Company-search-trial.jsx)
import React from "react";
import Blaze from "meteor/gadicc:blaze-react-component";
import "./pages/search.html";
import Companies from "../api/data/companies.js";
import CompaniesIndex from "../api/data/index.js";
/* A set of controls for the user to select search queries and options.
* For use in the CompanySearchPage.
*/
Template.search.rendered = function() {
$("#search-link").addClass('selected');
$("#profile-link").removeClass('selected');
$("#rankings-link").removeClass('selected');
$("#jokes-link").removeClass('selected');
$("#login-link").removeClass('selected');
}
Template.search.helpers({
inputAttributes: function() {
return { 'class': 'easy-search-input', 'placeholder': 'Start Searching' };
},
players: function() {
return Companies.find({}, { sort: { createdAt: -1 } });
},
selectedName: function() {
var company = CompaniesIndex.config.mongoCollection.findOne({ __originalId: Session.get("selectedCompany") });
return company && company.Name;
},
index: function () {
return CompaniesIndex;
},
resultsCount: function() {
return CompaniesIndex.getComponentDict().get('count');
},
showMore: function() {
return false;
},
renderTmpl: () => Template.renderTemplate
});
Template.User.helpers({
selected: function() {
return Session.equals("selectedCompany", this.__originalId) ? "selected" : '';
},
});
Template.User.events({
'click': function() {
Session.set("selectedCompany", this.__originalId);
}
});
export default class CompanySearchTrial extends React.Component {
render() {
return (
<div className="page CompanySearchTrial">
<Blaze template="search"/>
</div>
);
}
}
Can someone please help me with this. I am really clueless, as to how to go about doing this. Thanks!
The error: Match error: Expected particular constructor" points to a likely cause of an invalid parameter to a function. It also gives us the pointer that it's a missing constructor that's the issue.
The two things in your code that use constructors (ie. are instantiated with new) are EasySearch.Index and EasySearch.MongoDBEngine.
Taking a quick look at the documentation for EasySearch, the correct way to import both of these classes is like so:
import { Index, MongoDBEngine } from 'meteor/easy:search'
// Client and Server
const index = new Index({
...
engine: new MongoDBEngine({
sort: () => { score: 1 },
}),
});
Give the above a go and see if it solves your issue
Well, I'm fairly new to both angular and breeze and I have an entity called Collection with a navigation property products since a collection can have many products in it.
So when I click a button I want to add that product to that collection but I haven't had any luck with it, I read breeze.js documentation and apparently doing something like
collection.products.push(product)
should work, but it's not working any thoughts on this?
this is the entity definition
addType({
name: 'Collection',
defaultResourceName: 'collections',
dataProperties: {
id: { type: ID },
name: { max: 255, null: false },
slug: { max: 255 },
productsCount: { type: DT.Int16 }
},
navigationProperties: {
products: {
type: 'Product',
hasmany: true
}
}
})
This is the code that actually tries to add the item to the products
function addToCollection(product){
logSuccess('Product added to collection');
//trying to put a product into the collection products, with no luck
vm.collection.products.push(product);
}
And this is the template where the products are listed and the user can add them to the collection.
tbody
tr(ng-repeat="product in vm.products | inCollection:vm.filter_by")
td {{ product.master.sku }}
td {{ product.name }}
td {{ product.price | currency }}
td
img(data-ng-src="{{ product.master.images[0].mini_url }}")
td.text-center
.btn-group.btn-group-xs
a.btn.btn-default(data-ng-click="vm.addToCollection(product)")
i.fa.fa-plus
.btn-group.btn-group-xs
a.btn.btn-default(data-ng-click="vm.removeFromCollection(product)")
i.fa.fa-minus
I've been debugging and breeze is not returning any goodAdds so it won't add it to the collection, any ideas on why this is not a goodAdd? BTW, collections N -> N products.
As far as I know breeze doesn't support modification through Navigation properties So what you need to have is 2 types .. Collection and Property..
addType({
name: 'Proeprty',
defaultResourceName: 'properties',
dataProperties: {
id: { type: ID },
collectionId: { type: int32}
},
navigationProperties: {
collection: {
type: 'Collection',
isScalar: true
}
}
})
then when you want to add onto it you just make sure you set the collectionId
Breeze's Navigation Properties aren't like typical relationships
In my AngularJS application, I am displaying contacts data in a grid. My typical contacts JSON looks like as below ...
[
{ type: "IM", value: "mavaze123", default: true },
{ type: "IM", value: "mvaze2014", default: false },
{ type: "IM", value: "mavaze923", default: false },
{ type: "IM", value: "mvaze8927", default: false },
{ type: "Email", value: "mavaze123#abc.com", default: true },
{ type: "Email", value: "mvaze2014#xyz.net", default: false }
]
The last property 'default' is actually a radio button, selection of which should alter the original default value of the corresponding contact type in above JSON. There can be one default from each type of contact i.e. we can group radio buttons based on the contact type.
<div ng-repeat="contact in contacts">
<div>{{contact.type}}</div>
<div>{{contact.value}}</div>
<div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="true"/></div>
</div>
Note: The above code is not the exact one, but approximately same, as
it will appear inside a custom grid component.
Now when I load my view/edit form page with above JSON, it correctly shows the radio state of all contacts. The problem comes, after page load, when user selects another contact as default. This actually changes the model value of default to true for newly selected contact however the model value of original default contact still remains true, even though its radio state changes to uncheck/blur (because they are having same 'name' value).
I thought to write a directive, but I am unable get it triggered on radio on-blur/uncheck event.
There are various posts on binding boolean values to radio buttons, but I am unable to get it work in my scenario, as I want to update model values for individual radio button in a radio group. See there is no single model representing a radio group.
I think you should change your design to separate the contacts from contactTypes and store the key to the default contact in contact type.
In your current design, there are duplicated values for default and that's not the desired way to work with radio.
$scope.contacts = [
{ type: "IM", value: "mavaze123" },
{ type: "IM", value: "mvaze2014" },
{ type: "IM", value: "mavaze923" },
{ type: "IM", value: "mvaze8927" },
{ type: "Email", value: "mavaze123#abc.com" },
{ type: "Email", value: "mvaze2014#xyz.net" }
];
$scope.contactTypes = {
"IM": { default:"mavaze123"}, //the default is contact with value = mavaze123
"Email": { default:"mavaze123#abc.com"}
};
You Html:
<div ng-repeat="contact in contacts">
<div>{{contact.type}}</div>
<div>{{contact.value}}</div>
<div><input type="radio" name="{{contact.type}}" ng-model="contactTypes[contact.type].default" ng-value="contact.value"/></div>
</div>
DEMO
I assume that the key of contact is value, you could use an Id for your contact.
I added an attribute directive in my input statement ...
<div ng-repeat="contact in contacts">
<div>{{contact.type}}</div>
<div>{{contact.value}}</div>
<div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="true" boolean-grid-model /></div>
</div>
And my custom directive ...
myModule.directive('booleanGridModel') {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, controller) {
var radioSelected = scope.$eval(attrs.ngModel);
if(radioSelected) {
var selectedContact = scope.contact;
_.each(scope.contacts, function(contact) {
if(contact.type === selectedContact.type) {
_.isEqual(contact, selectedContact) ? contact.default = true : contact.default = false;
}
});
}
}
};
}
WHy you declare ng-value="true" please remove that
<div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="{{contact.default}}"/></div>
Please use $scope.$apply() in your value changing code
Like something below
$scope.$apply(function ChangeType()
{
/Code
});
And you need to change name="{{contact.type}}" to name="contact.type{{$index}}" Because some types are same name.