Jsviews filter search - search

How do I create a filter search in JSViews? Usually I'd grab the html element by its class with the .getElementsByClassName() and .value() methods and add a === comparison to satisfy the right criteria. How can I do something similar in JsViews
I've already tried to add listItem in the IF to match the value of the html input (search bar), but I don't know how to grab the value of the search element (JQuery would be easy using $(".search")), or compare it to the listItems using regExp.
{^{if list && list.length}}
<ul autoselectitem="true" tabindex="-1" operationalindex="1" allindex="1">
{^{for list}}
{{include tmpl="listItem" /}}
{{/for}}
</ul>
{{else}}
<p>Nothing Found</p>
{{/if}}
This currently displays all items in the list, however I only want the elements in the list to be displayed that match with RegEx the .value of an search HTML element:
<input type="text" class="search" data-link="search" placeholder="Search...">
So for example, if I type in "e" into the search bar, all the items in the list that don't have the letter "e" should disappear.
The code linked all work, but what i've tried has given me null pointer errors because I'm not grabing the input element correctly by its class or data-link. How could I do this in the simplest way possible? Thanks

Here is one way of doing it:
<script id="myTmpl" type="text/x-jsrender">
<input type="text" class="search" data-link="search" placeholder="Search...">
{^{if list && list.length}}
<ul autoselectitem="true" tabindex="-1" operationalindex="1" allindex="1">
{^{for list filter=~flt depends="search"}}
<li data-link="#data"></li>
{{/for}}
</ul>
{{/if}}
</script>
<div id="page"></div>
<script>
var myTmpl = $.templates("#myTmpl"),
data = {
list: ["a", "b"],
search: ""
},
helpers = {
flt: function(item, index, items) {
return item.indexOf(data.search) > -1;
}};
myTmpl.link("#page", data, helpers);
</script>

Related

How can I render specific piece of data from my mongodb into my html?

It's my first project. I'm creating a website where administrator have the privilege to change home page texts. So I'm keeping all texts in a collection called "Texts" , each document has a text:value . When home page is rendered I use Texts.find() to return an array containing objects each has a "text" value. I link it to my home page using index.
Like this..
<h2>Texts[0].text</h2>, so if i have 100 texts I go all the way to <h2>Texts[100].text</h2>. and they are different texts and I need to put them in a specific order so I can't just throw them into my html.
I know that's so stupid , so I'm looking for some idea instead of this.
--------------Modification------------------>>>>
I tried using find method for arrays but it also is so tiring , so something simpler would be great , here's a portion of the code
<div class="card bg-dark text-white">
<img src="<%=imgsArr.find(x => x.name === 'main2').src%>" class="card-img" alt="...">
<div class="card-img-overlay ">
<h2 class="card-title"><%=textArr.find(x => x.id === 14).text%></h2>
<div class="triangle-up"></div>
<hr class="ml-0 ">
<div class="triangle-down"></div>
<p class="card-text "><%=textArr.find(x => x.id === 15).text%></p>
<div class="card-topic">
<h2 class="card-title" style=";"><%=textArr.find(x => x.id === 16).text%></h2>
<p class="card-text"><%=textArr.find(x => x.id === 17).text%></p>
</div>
<div class="card-topic">
<h2 class="card-title" style=""><%=textArr.find(x => x.id === 18).text%></h2>
<p class="card-text"><%=textArr.find(x => x.id === 19).text%></p>
</div>
<div class="btnOut ">
<button class="btn btn-lg shadow-lg ">MENU</button>
</div>
</div>
</div>
Good news is that for loops are always a good option. If you are using ejs or a similar rendering engine something like this should work, although you will have to tweak it a bit. Take a look are the EJS rendering engine documentation for an exact format, but it would look something like below and no matter how long the list gets it will render as much as it receives(if it is a lot you might want to consider using pagination)
<% for text in Texts.text %>
<% if text==="some value"%>
<h2>text</h2>
<% else %>
<p> text </p>
If your front-end is perhaps react.js or vue.js or similar the same prnciple would work but the format will be different.
No offense friend but you need to get some tutorials. But let me help you as best i can. Everything in a web application is somewhat defined. Meaning it falls into one predetermined category or another. When you get json for example you get something base on how that particular data is defined in the database. Hence you can get json data from your backend that looks
{ 'title':'sneaker', 'price':'200', 'quantity':'50' }
Now assuming it is a list of json objects what you can do is loop through this and assign them to tags based on their object key(because it gets converted to a javscript object). so again you code would look something like
<% for text in Texts.text %>
<h2>text.title</h2>
<div>
<p>text.price</p>
<p>text.quantity</p>
</div>
This would be how you would render data from your database(the format might not exactly be spot on). Dealing with forms is a whole other ball game. So get a book or some tutorial videos that discuss it. You will better understand how to handle it.
For your code you are being very rigid, at first glance there is already a pattern, work with that pattern, you code just needs a simple for loop from what i gather.
for(let i=0; let i>100; i++){
if (i%2===0){
console.log(<h2> i </h2>)
}else{
console.log(<p> i </p>
}
}
The reason i have resulted to pure javascript is so you can see what the inner workings of your render should look like. You can get the total number of ids in your database(that is what the integer 100 represents in this case), loop through one by one and produce what you want. It is still javascript, do not let the html throw you off

If element hasClass, add another class to its title value

I'm using slick carousel, and once a div is active I want to open the corresponding description.
Problem I'm having is with this code:
if ($('div').hasClass('active')) {
var title = $(this).attr('title');
$('ul li').removeClass('open');
$(title).addClass('open');
}
What I'm trying to achieve:
Once a div gets class 'active', I want to take its title value, and use it as a id link to list element I want to display(add class to).
Here is a FIDDLE.
Use event handling, not class monitoring.
The slick carousel API has events for this, I believe you want to use the afterChange event to act on the active element after it has been made visible.
Check out the docs and examples, especially the section titled "Events" on Slick page: http://kenwheeler.github.io/slick/
And I think you don't want to use title attribute for this because that is for tooltips. I recommend data-* attributes instead. And element IDs should generally start with a letter and not a number (was required in HTML4 and makes life easier when mapping IDs to JavaScript variables; though if you are using HTML5 I think this requirement is no longer in effect).
HTML
<div id="carousel">
<div data-content-id="content1">
Selector 1 </div>
<div data-content-id="content2">
Selector 2 </div>
<div data-content-id="content3">
Selector 3 </div>
</div>
<ul class="content">
<li id="content1">Content 1</li>
<li id="content2">Content 2</li>
<li id="content3">Content 3</li>
</ul>
JavaScript
$('#carousel').on('afterChange', function(event, slick, currentSlide) {
// get the associated content id
var contentId = $(slick.$slides.get(currentSlide)).data("content-id");
if(contentId && contentId.length)
{
var $content = $("#" + contentId);
$(".content>li").removeClass("open"); // hide other content
$content.addClass("open"); // show target content, or whatever...
}
});
I have found a solution:
$('.slider').on('afterChange', function(event, slick, currentSlide, nextSlide){
var contentId= $(slick.$slides.get(currentSlide)).data('content');
if(contentId)
{
$(".content li").removeClass('open');
$('#' + contentId).addClass('open');
}
});
Working fiddle

cheerio selection of a list

On a page I need to scrape (with node.js and cheerio), I have this pattern:
<h2>
<span id="2015"></span>
<span class="ignore-me"></span>
</h2>
<div>
<ol>
<li>
<a title="TITLE1" href="HREF1"></a>
<a class="image" title="ignore-me-1" href="ignore-me-1"></a>
</li>
...
<li>
<a title="TITLE2" href="HREF2"></a>
<a class="image" title="ignore-me-2" href="ignore-me-2"></a>
</li>
</ol>
</div>
I would like to extract a list with TITLEs an HREFs.
I am trying something like this:
$('h2 > span[id="2015"]').next('ol > li > a').each(function(index, element) {
console.log('title:', element.attr('title'), 'href:', element.attr('href'));
});
without success (each loop is never entered...).
Any suggestion?
The ol element isn't actually the next element of span#2015. The ol element is inside a div which is the next element of h2. The right tree traversal is :
$('h2 > span[id="2015"]')
.parent()
.next('div')
.find('ol > li > a:not([class])')
.each(function() {
var $el = $(this);
console.log('title:', $el.attr('title'), 'href:', $el.attr('href'));
});
The h2 tag does not have an ID, thus your selector finds no results, nothing to loop over.
You could easily do it by looping anchor tags.
$("a").each(function(i, e) {
if (e.attr('title') && e.attr('href')) console.log("... stuff ...");
});
Or you can give your h2 an id, or remove the id from your selector. Many ways to loop.

How to check type of object in Handlebars?

I am currently working on a search bar that lists three types of objects: users, records and locations. Each has its own model and such defined, with corresponding controllers. What I need to do is to check which type of object it is because I need the HTML that renders with it to be different.
{{#each mainUserSearchResults}}
{{#link-to 'user' this.userID}}
<div class="row mainListSeperator" {{action "getapplicantUserID" this target="view"}}>
<img class="applicantsIcon" src="">
<div class="applicantsName">
{{unbound this.firstName}} {{unbound this.lastName}}
</div>
<div class="applicantsTitle">
User
</div>
</div>
{{/link-to}}
{{/each}}
The only issue I am having is that I need it to print this.firstName & this.lastName if it is a user, but I cannot do that for records. For records, I would have to render another property - this.recordID - in the same manner as I did this.firstName. The way to do this would be an if conditional, but I cannot find anything in HandleBars that allows me to check whether the data coming in from mainUserSearchResults is a user or a record.
The mainUserSearchResults is a property in my controller that returns an array of objects: currently it return a concatenated array of user objects and record objects.
Handlebars is a logicless template, so you really can't perform computations, like type-checking. There are some pretty good reasons for this. If it were me, I'd push that responsibility elsewhere, probably all the way to your model, for two reasons:
Any conditionals you put in the DOM are SLOW. The problem only gets compounded when you're on slow devices (most notably, mobile).
Every time you add a new searchable thing, you're going to have to update your templates. Over time, you'll end up with:
{{#if ...}}
...
{{/if}}
{{#if ...}}
...
{{/if}}
{{#if ...}}
...
{{/if}}
{{#if ...}}
...
{{/if}}
Delegate instead. For example, in your User model, add
formattedName: (function() {
return [this.get('firstName'), this.get('lastName')].join(' ');
}).property('firstName', 'lastName')
Do the same for your records and locations.
Then, change your template from
{{unbound this.firstName}} {{unbound this.lastName}}
to
{{unbound this.formattedName}}
Now, if you add new types to your searches, you have a completely generic solution that only needs the model to implement the formattedName property.
Some would would say my suggestion is a bad one, because it mixes the business-logic responsibility of a model with display logic. In this case, I'm guessing you're displaying {{firstName}} {{lastName}} in more than one place, so I think the benefits of keeping your code DRY outweigh moving this to, e.g., a controller. Your call.
Assuming there is some way to easily distinguish between the 2+ types of objects, you can use an if statement and render a different template (or even use a different partial, http://emberjs.com/guides/templates/rendering-with-helpers/)
<script type="text/x-handlebars" data-template-name="index">
<ul>
{{#each item in model}}
<li>
{{#if item.foo}}
{{render 'foo' item}}
{{/if}}
{{#if item.cow}}
{{render 'cow' item}}
{{/if}}
</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="foo">
I'm a foo: {{foo}}
</script>
<script type="text/x-handlebars" data-template-name="cow">
I'm a cow: {{cow}}
</script>
http://emberjs.jsbin.com/qinilege/1/edit
Or if you need more advanced checking you can use an item controller and add the logic in there
{{#each item in model itemController='checker'}}
<li>
{{#if item.isFooBar}}
{{render 'foo' item.model}}
{{/if}}
{{#if item.isFooBaz}}
{{render 'fooz' item.model}}
{{/if}}
{{#if item.isCow}}
{{render 'cow' item.model}}
{{/if}}
</li>
{{/each}}
App.CheckerController = Em.ObjectController.extend({
isFooBar: Ember.computed.equal('foo', 'bar'),
isCow: Ember.computed.notEmpty('cow'),
isFooBaz: Ember.computed.equal('foo', 'baz')
});
http://emberjs.jsbin.com/qinilege/2/edit

Strange results with nested handlebar blocks in Meteor

I am trying to set default value in an html select, but without sucess.
I'm doing the initial populating like this:
<template name="demo">
<select>
{{#each foo}}
<option>{{this}}</option>
{{/each}}
</select>
</template>
And i set the possible options in the model like this:
Template.demo.foo = ["aaa","bbb","ccc"];
So far, everything work as intended.
Now i'm trying to display row of the collection collec, populating the select with the defaut recorded foo value (aaa or bbb or ccc).
My understanding is that you must add "selected" to the tag.
So i do something like this with multiple nested blocks:
<template name="demo">
{{#each collecs}}
{{_id}}
<select>
{{#each foos}}
<option{{#if isSelected this ../this}}selected{{/if}}>{{this}}</option>
{{/each}}
</select>
{{/each}}
</template>
And on the model front:
Template.demo.foos = ["aaa","bbb","ccc"];
Template.demo.collecs = function(){
return Collec.find({});
};
Template.demo.isSelected = function(fooToCheck, record){
var rid= record._id;
var currentRecord = Collec.findOne({_id:rid});
return (fooToCheck==currentRecord.foo);
};
The problem is that it does not work.
The dropdown stays empty, and the generated html code show something like this:
" >aaa "
I have checked in the js part, all seems to work correctly, true/false are adequately returned.
Thank in advance for your help.
Handlebars conditionals don't do well inline. In fact, I'm not sure if they work inline anywhere. What was happening was that the Handlebars templating engine didn't understand your html, so it skipped over it, which is why you saw '>aaa'.
The following code works. I took the liberty of simplifying your isSelected function.
Template:
<template name="demo">
{{#each collecs}}
{{_id}}
<select>
{{#each foos}}
{{#if isSelected this ../foo}}
<option selected>{{this}}</option>
{{else}}
<option>{{this}}</option>
{{/if}}
{{/each}}
</select>
{{/each}}
</template>
JavaScript:
Template.demo.foos = ["aaa","bbb","ccc"];
Template.demo.collecs = function(){
return Collec.find({});
};
Template.demo.isSelected = function(fooToCheck, recordFoo){
return (fooToCheck === recordFoo);
};

Resources