Meteor - Trying to automate using data attributes and ReactiveDict - javascript

I'm trying to automate naming conventions used for a reactive dictionary, but I'm stuck not knowing how to access the reactive dictionary key based on the data attribute I fetched on click.
Expected: Use same naming convention for both ReactiveDict keys and data-attribute names on HTML elements so I can fetch the name on the element clicked, take its data-attribute name and automatically know which ReactiveDict key it is because they use the same name.
Result: It's not recognizing the naming convention when trying to set or get from the ReactiveDict because... I don't know. I'm guessing it's because when you create a ReactiveDict, you use this convention template.search.set('generic_name', data) but it won't work if I replace 'generic_name' with the data-attribute name (that doesn't include the single quotes) on click.
Please see example code below and advise if you have any questions, request for more info, or funny jokes since we're all trapped at home avoiding the COVID-19 virus :slight_smile:
home-template.html
<template name="home_template">
<section class="home-template">
<div class="content">
<div class="filter-box">
<ul>
<legend class="sui-category__title">CATEGORY 1</legend>
{{#each option in category_one}}
<li data-filter-value="{{option.value}}" data-category-name="category_one">
<div class="circle">{{formatToNumberWithComma(option.count)}}</div>
<h4>{{option.value}}</h4><input id="filter-1-{{get_this(option)}}" type="checkbox" /><label for="filter-1-{{get_this(option)}}"><i class="fa fa-check"></i></label>
</li>
{{/each}}
</ul>
<span class="more-options">+ More</span>
</div>
<div class="filter-box">
<ul>
<legend class="sui-category__title">CATEGORY 2</legend>
{{#each option in category_two}}
<li data-filter-value="{{option.value}}" data-category-name="category_two">
<div class="circle">{{formatToNumberWithComma(option.count)}}</div>
<h4>{{option.value}}</h4><input id="filter-2-{{get_this(option)}}" type="checkbox" /><label for="filter-2-{{get_this(option)}}"><i class="fa fa-check"></i></label>
</li>
{{/each}}
</ul>
<span class="more-options">+ More</span>
</div>
<div class="filter-box">
<ul>
<legend class="sui-category__title">CATEGORY 3</legend>
{{#each option in category_three}}
<li data-filter-value="{{option.value}}" data-category-name="category_three">
<div class="circle">{{formatToNumberWithComma(option.count)}}</div>
<h4>{{option.value}}</h4><input id="filter-3-{{get_this(option)}}" type="checkbox" /><label for="filter-3-{{get_this(option)}}"><i class="fa fa-check"></i></label>
</li>
{{/each}}
</ul>
<span class="more-options">+ More</span>
</div>
</div>
</section>
</template>
home-template.js
Template.home_template.onCreated(() => {
const template = Template.instance();
template.search = new ReactiveDict();
template.search.set('category_one');
template.search.set('category_two');
template.search.set('category_three');
template.search.set('filter_parameters');
});
Template.home_template.helpers({
formatToNumberWithComma(number) {
return format_w_comma(number);
},
category_one() {
const template = Template.instance();
return template.search.get('category_one')[0].data;
},
category_two() {
const template = Template.instance();
return template.search.get('category_two')[0].data;
},
category_three() {
const template = Template.instance();
return template.search.get('category_three')[0].data;
},
get_this(option) {
const query_to_array = [];
const search_query_word_array = option.value.split(' ');
const search_query_word_array_count = search_query_word_array.length;
for (let i = 0; i < search_query_word_array_count; i++) {
query_to_array[i] = `${search_query_word_array[i]}`;
}
const search_query = query_to_array.join('-');
return search_query;
},
});
Template.home_template.events({
'click .home-template label': function (event, template) {
$(event.currentTarget).parent('li').toggleClass('active');
const category_clicked = $(event.currentTarget).parent('li')[0].dataset.categoryName;
const filter_selected = $(event.currentTarget).parent('li')[0].dataset.filterValue;
const array = template.search.get(category_clicked);
array.indexOf(filter_selected) === -1 ? array.push(filter_selected) : array.splice(array.indexOf(filter_selected), 1);
template.search.set(category_clicked, array);
const filter_parameters = {
filters: {
all: [{
category_one: template.search.get('category_one'),
},
{
category_two: template.search.get('category_two'),
},
{
category_three: template.search.get('category_three'),
},
],
},
};
template.search.set('filter_parameters', filter_parameters);
},
});
Thank you!

You data keys are working, you actually set the data here:
const category_clicked = $(event.currentTarget).parent('li')[0].dataset.categoryName
const filter_selected = $(event.currentTarget).parent('li')[0].dataset.filterValue
const array = template.search.get(category_clicked)
array.indexOf(filter_selected) === -1
? array.push(filter_selected)
: array.splice(array.indexOf(filter_selected), 1)
template.search.set(category_clicked, array)
Consider the following data:
template.search.set('category_one', [
{
data: [
{
value: 'some value here',
count: 100
}
]
}
])
and category_clicked to be category_one and filter_selected to be some value here then the code above will result in the following data:
[
{
data: [
{
value: 'some value here',
count: 100
}
]
},
'some value here'
]
I am not sure how you further process this data but this shows your reactive data is working. The data updated in the helper right after your clicked the label.

Related

How do I toggle a knockout foreach div individually without adding more html?

I used the foreach method to create markup foreach item in an observable array to create a treeview.
output example
category name1
content
content
category name 2
content
content
when I click on the category name I want just its content to show/hide, currently when I click on the category name it shows and hides all the categories.
var reportFilters = [
{ Text: "Campaign", Value: primaryCategories.Campaign },
{ Text: "Team", Value: primaryCategories.Team },
{ Text: "Agent", Value: primaryCategories.Agent },
{ Text: "List", Value: primaryCategories.List },
{ Text: "Inbound", Value: primaryCategories.Inbound },
{ Text: "Daily", Value: primaryCategories.Daily },
{ Text: "Services", Value: primaryCategories.Services },
{ Text: "Occupancy", Value: primaryCategories.Occupancy },
{ Text: "Data", Value: primaryCategories.Data }
];
self.showCategory = ko.observable(false);
self.toggleVisibility = function (report) {
var categoryName = report.PrimaryReportCategory;
var categoryContent = report.ID;
if (categoryName == categoryContent ) {
self.showCategory(!self.showCategory());
};
}
<div class="report-category-treeview" data-bind="foreach: $root.categories, mCustomScrollBar:true">
<ul class="column-list" >
<li class="report-category-heading" data-bind="click: $root.toggleVisibility"><span class="margin-top10" ><i class="fas fa-chevron-down"></i> <span class="report-category-name" data-bind="text: categoryName"></span></span></li>
<li id="panel" class="report-category-container" data-bind="foreach: reports, visible: $root.showCategory">
<div class="column-list-item" data-bind="click: $root.report_click, css: { 'selected': typeof $root.selectedReport() != 'undefined' && $data == $root.selectedReport() }">
<span class="column-list-text" data-bind="text: ReportName"></span>
</div>
</li>
</ul>
</div>
currently, when I click on the category name, it shows and hides all the
categories.
It's because showCategory is your single observable responsible for showing\hiding. What you really want is one show\hide observable per category.
I'm not sure how your entire data model looks like, but since you specifically asked about categories, then you should create a category view model, and probably some container view model, which I'll name here master:
var categoryVM = function (name) {
var self = this;
self.name = ko.observable(name);
self.isVisible = ko.observable(false);
self.toggleVisibility = function () {
self.isVisible(!self.isVisible());
}
// ... add here your other observables ...
}
// name 'masterVM' whatever you like
var masterVM = function () {
var self = this;
self.categories = ko.observables([]);
// ... probably add here other observables, e.g. 'reports' ...
self.init = function (rawCategories) {
rawCategories.forEach(function (item) {
categories.push(new categoryVM(item.name)); // replace 'name' with your property
}
}
}
var master = new masterVM();
master.init(getCategories()); // pass in your categories from wherever they come from
ko.applyBindings(master);
Then, in your html, this would be your outer foreach:
<div class="report-category-treeview" data-bind="foreach: categories ... />
and your lis (for brevity, I'm ommiting nested tags under your lis):
<li class="report-category-heading"
data-bind="click: toggleVisibility">
<li id="panel" class="report-category-container"
data-bind="foreach: $root.reports, visible: isVisible">

Cheerio: .text() appends all of the elements' text together

The code below outputs all of the p tags with staff-member-title appended
let arr = [];
$("li.staff-directory-department").map((item, index) => {
arr.push({
title: $("p.staff-member-title", index).text()
});
});
console.log(arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="staff-directory">
<li class="staff-directory-department">
<h2 class="staff-directory-department">
Academic Affairs
</h2>
<ul class="staff-directory-department-list">
<li class="staff-member ">
<a href="" class="staff-member-image">
<img src="" />
</a>
<h3 class="staff-member-name">
Meli
</h3>
<p class="staff-member-title">Director of Institutional Research & Effectiveness</p>
<p class="staff-member-email">
</p>
<p class="staff-member-phone">(90</p>
</li>
</ul>
</li>
</ul>
Current output for arrayInfo:
[
{ title: 'Director of Institutional Research & EffectivenessAdministrative AssistantDirector of Online Learning and Educational TechnologyAssociate Vice President of Academics and Strategic InitiativesVice President for Academics & Student Life' },
{ title: 'Director of Institutional Research & EffectivenessAdministrative AssistantDirector of Online Learning and Educational TechnologyAssociate Vice President of Academics and Strategic InitiativesVice President for Academics & Student Life' },
...
]
Expected output:
[
{ title: 'Director of Institutional Research & Effectiveness' },
{ title: 'Administrative Assistant' },
...
]
I believe your problem is that you're creating a dictionary with Javascript, but giving one key to multiple items, and so when that key is called you're pulling up each item associated with that key.
What you may want to try instead is to put all of the Titles into an array, and then associate that array with the key Title, so that when you call the key Title you can sift through the array of all the Titles.
let arr = [];
let titleArr = [];
$("li.staff-directory-department").map((item, index) => {
titleArr.push({
$("p.staff-member-title", index).text()
});
});
arr.push({title: titleArr});
then when you want to grab the titles just call the array using the key:
for(var x = 0; x < titleArr.length; x++){
console.log(arr["title"][x]);
}
You're mixing up the arguments, index comes first in Cheerio.map:
let arr = $('li.staff-directory-department').map((i, el) => {
return { title: $(el).find('p.staff-member-title').text() }
}).get()
It might be simpler to use Array.map
let arr = $('li.staff-directory-department').get().map((el) => {
return { title: $(el).find('p.staff-member-title').text() }
})
Note: get() turns the cheerio object into an array.

How to expand single statement for multiple statements in success function

I'm trying to turn the results of a route from my API into a searchable list the whole process of obtaining data via AJAX is completed, I can print data on my front end but only 1 result from my list in JSON is available to the client, how can I expand this list using statement?
Jquery
$('#sendSearchAddress').click(function() {
$.ajax({
type: "GET",
dataType: "JSON",
url: "https://****/api/itapetininga-street-last-three-searcheds?access_token=7Z***",
success: function (finalData) {
// Running test
console.log(finalData);
if (finalData) {
// var dd = JSON.parse(result);
// alert(finalData[0].addressStreet)
// name: finalData[0].addressStreet
// Print Results
var options = {
valueNames: ['name', 'born']
};
// Example One
var values = [{
name: finalData[0].addressStreet
}];
var userList = new List('users', options, values);
// Example Two
// userList.add(values);
// Print Varible Contain Data From Street
console.log(values);
}
}
});
});
Html
<div id="users">
<input class="search" placeholder="Search" />
<button class="sort" data-sort="name">
Sort by name
</button>
<button id="sendSearchAddress">
Atualizar
</button>
<ul class="list">
<li>
<h3 class="name">Jonny Stromberg</h3>
<p class="born">1986</p>
</li>
<li>
<h3 class="name">Jonas Arnklint</h3>
<p class="born">1985</p>
</li>
</ul>
</div>
My JSON Result
I'm not sure I fully understand what you're trying to do but as best as I can tell it looks like you need to change
var values = [{
name: finalData[0].addressStreet
}];
to
var values = finalData.map(function(finalDatum) {
return {
name: finalDatum.addressStreet
};
});

Vue Js binding 2 values to a tag href

I'm beginner on Vue js. I'm facing an issue where I have to update two values while rendering.
<ul class="category-list">
<li v-for="category in categories">
<a v-bind:href="location/category.slug/all" v-text="category.name"></a>
</li>
</ul>
My javascript file
new Vue({
el : '#example',
data : {
location: 'new-york',
categories: [],
},
mounted() {
axios.get('parent-categories').then((response) => {
this.categories = response.data;
});
},
});
Ajax Response
[{"name":"Default Category","slug":"default-category"},{"name":"Main Category","slug":"main-category"}]
Here I wanted to build url structure like location/category-slug/all ie,
http://myapp.com/new-york/default-category/all
How to achieve this?
Found out how to handle this situation after a long struggle. All I have to do is to create a method that generates URL for me.
JS
new Vue({
el : '#example',
data : {
location: 'new-york',
categories: [],
},
methods: {
slug: function (category) {
return this.location+'/'+category.slug+'/all';
}
},
mounted() {
axios.get('parent-categories').then((response) => {
this.categories = response.data;
});
},
});
Html
<div id="example">
<h3>Services</h3>
<ul class="category-list">
<li v-for="category in categories">
<a :href="slug(category)" v-text="category.name"></a>
</li>
</ul>
</div>

v-for through an object in vue.js

I have a Teams object, which has a record of all teams and can also count and create them. I store all teams as an object, so I can write Teams.all["Team 1"] to select a team with a name of "Team 1".
Teams.js
var Teams = {
all: {},
create: function(teamName) {
var key = 'Team ' + this.count();
this.all[key] = {
'name': teamName,
'score': 0
};
},
count: function() {
var total = 0;
for(var team in this.all){
if(this.all.hasOwnProperty(team)){
total ++;
}
}
return total;
}
}
Now in vue I'd like to loop through this.
main.js
var vueApp = new Vue({
el: '#app',
data: {
'Teams' : Teams
},
methods : {
createTeam : function(){
Teams.create('Team ' + (Teams.count() + 1));
}
}
});
And then this doesn't work (obviously):
index.html
<div id="app">
<ul>
<li v-for="team in Teams.all">{{ team.name }}</li>
</ul>
<button #click="createTeam">Create team</button>
</div>
So my next guess was to go like this:
index.html
<div id="app">
<ul>
<li v-for="team in Teams.all">{{ Teams.all[team].name }}</li>
</ul>
<button #click="createTeam">Create team</button>
</div>
But that doesn't work either. Is there a way to loop through the properties of an object in Vue?
http://codepen.io/EightArmsHQ/pen/wzPKxA
Your Teams state is not reactive because you are adding object keys to it... Read this docs here: http://rc.vuejs.org/guide/reactivity.html#Change-Detection-Caveats.
Use this.$set(this.someObject, 'b', 2) if you want to add properties to your state object or those won't be reactive and trigger view update.
Also not sure why you complicate so much :). Try this:
var vueApp = new Vue({
el: '#app',
data: {
teams: []
},
methods: {
addTeam: function() {
this.teams.push({
name: 'Team ' + this.teams.length,
score: 0
})
}
}
});
<div id="app">
<ul>
<li v-for="team in teams">
{{ team.name }}
</li>
</ul>
<button #click="addTeam">Create team</button>
</div>
Demo here: http://codepen.io/anon/pen/qaVbym

Categories

Resources