I need to be able to type in a query in the search textfield in my web app and return highlighted results from each document that has the specific text. The problem is, I can't get the response to show all documents, it only shows one.
Lets say I have 4 documents with ID of doc1, doc2, doc3, doc4 etc. How can I get the code to loop through to display content from all 4 documents rather than just one. I've hardcoded doc2 into my program to get it to work, I'm having trouble looping through it.
Ext.data.JsonP.request({
url: 'http://localhost:8983/solr/collection1/select?q='+searchValue+'&wt=json&indent=true&hl=true&hl.fl=content&hl.simple.pre=%3Cem%3E&hl.simple.post=%3C%2Fem%3E',
callbackKey: "json.wrf",
success: function( res, req ) {
for (i=0; i<res.response.numFound; i++) {
var docId = res.response.docs[i].id;
//This returns all ids. ex. doc1, doc2 etc.
alert(docId);
htmlCode += "<h4>Your search term: "+searchValue+"</h4><p>"+res.highlighting.doc2.content+"</p>";
}
//Print code below -- irrelevant for the question.
}
You can try to directly iterate on the res.response.docs collection.
e.g. JQUery JSON Example
$.each(data.response.docs, function(key, element){
console.log(element.id);
});
Figured it out from this post: How do I access properties of a javascript object if I don't know the names?
I included this in my for loop to get it working:
var hl = res.highlighting;
var content="";
Object.keys(hl).forEach(function (key) {
if(key == docId) {
content = hl[key].content;
}
});
Related
I have an array of objects:
scope.values = [
{'key1':'valueA', 'key2': 'valueD'},
{'key1':'valueB'},
{'key1':'valueC'}
]
And I would like to filter a search input, which can contain multiple words separated by either comma or space:
<input ng-model="scope.search"></input>
We can list the array as follows:
<p ng-repeat="index, obj in scope.values | filter:scope.search"></p>
However, this only works for one input. What can I do when I have multiple inputs e.g. John Doe.
Note that I want it to be conditional. So not if John or Doe is found, but when John and Doe are found.
I don't think the built-in filter can do that. What you probably want is a custom filter, as described in the documentation here (about half way down the page) and in the official tutorial here.
For example, this custom filter should do what you want.
app.filter("multiSearch", [
function() {
//"data" is your searchable array, and "search" is the user's search string.
return function(data, search) {
//Get an array of search values by splitting the string on commas and spaces.
var searchArray = search.toLowerCase().split(/[, ]/);
//Use javascript's native Array.filter to decide which elements to cut and to keep.
return data.filter(function(item) {
//If the item contains ALL of the search words, keep it.
var foundCount = 0;
for (var searchElement of searchArray) {
for (var attribute in item) {
if (
String(item[attribute])
.toLowerCase()
.includes(searchElement)
) {
foundCount++;
break;
}
}
}
if (foundCount === searchArray.length) {
//Matched all search terms. Keep it.
return true;
}
else {
//Not a match. Cut it from the result.
return false;
}
});
};
}
]);
Then in your html you can call it like so:
<p ng-repeat="index, obj in scope.values | multiSearch:scope.search"></p>
Another thing you might consider, as suggested in the comments, is to forego using filters altogether and just run the logic inside your controller. You can use a lot of the logic provided in the example filter above -- you just have to implement your own system to run the filtering logic when the search query changes. There are benefits in avoiding filters in angularjs, but that is another topic.
I am trying to access the following data in Vue.js
{"id":1,"name":"Westbrook","created_at":"2017-06-10T16:03:07.336Z","updated_at":"2017-06-10T16:03:07.336Z","stats":[{"id":1,"player_id":1,"points":2558,"assists":840,"rebounds":864,"created_at":"2017-06-10T16:03:07.373Z","updated_at":"2017-06-10T16:03:07.373Z"}]}
self.player = response.name works. now i need self.point
methods: {
fetchData: function() {
var self = this;
$.get("api/v1/players/1", function(response) {
console.log(response);
self.player = response.name;
self.point = response.stats.points
});
}
}
I have thus far tried response.stats["points"], response.stats[2], response.stats[ { points } ], response.stats[points]
The stats property in your json holds an array in which the first object has a property named points
So use response.stats[0].points
Keep in mind though that the stats is probably an array for a reason. It might hold more than one objects in the future, so always using the first element [0] might not be a valid approach.
I think it can help you
var json = JSON.parse(data);
json.stats[0].points
response = {"id":1,"name":"Westbrook","created_at":"2017-06-10T16:03:07.336Z","updated_at":"2017-06-10T16:03:07.336Z","stats":[{"id":1,"player_id":1,"points":2558,"assists":840,"rebounds":864,"created_at":"2017-06-10T16:03:07.373Z","updated_at":"2017-06-10T16:03:07.373Z"}]}
If you want to access the name
console.log(response.name) // Westbrook
If you want to access the stats data which contain list, simply target
let stats=response.stats[0] //By getting the first index in the list
Get the points in stats
console.log(stats.points) // 2588
So my question is: how do I scan the JSON in angular to find the first instance of isPrimary:true and then launch a function with the GUID that is in that item.
I have a webservice whos JSON defines available Accounts with a display name and a GUID this generates a dropdown select list that calls a function with the GUID included to return full data from a web service.
In the scenario where theres only 1 OPTION I dont show the SELECT and simply call the function with the single GUID to return the data from the service. If theres no options I dont show anything other than a message.
Code below shows what I currently have.
The Spec has now changed and the data they are sending me in the first service call which defines that select list is now including a property isPrimary:true on one of the JSON object along with its GUID as per the rest
I now need to change my interface to no longer use the SELECT list and instead fire the function call to the service for the item that contains the isPrimary:true property. However there may be multiple instances where isPrimary:true exists in the returning JSON so I just want to fire the function on the first found instance of isPrimary:true
Equally if that property isnt in any of the JSON items then just fire the function on the first item in the JSON.
My current Code is below - you can see the call to retrieve the full details is from function:
vm.retrieveAccount(GUID);
Where the GUID is supplied with each JSON object
Code is:
if (data.Accounts.length > 1) {
vm.hideAcc = false;
setBusyState(false);
//wait for the user to make a selection
} else if (data.Accounts.length == 1){
vm.hideAcc = true;
// Only 1 acc - no need for drop down get first item
vm.accSelected = data.Accounts[0].UniqueIdentifier;
vm.retrieveAccount(vm.accSelected);
} else {
// Theres no accounts
// Hide Drop down and show message
setBusyState(false);
vm.hideAcc = true;
setMessageState(false, true, "There are no Accounts")
}
Sample of new JSON structure
accName: "My Acc",
isPrimary: true,
GUID: "bg111010101"
Still think that's a weird spec, but simple enough to solve. Just step through the array and return the first isPrimary match. If none are found, return the first element of the array.
var findPrimary = function(data) {
if (!(Array.isArray(data)) || data.length == 0) {
return false; // not an array, or empty array
}
for (var i=0; i<data.length; i++) {
if (data[i].isPrimary) {
return data[i]; // first isPrimary match
}
}
// nothing had isPrimary, so return the first one:
return data[0];
}
I want to split a list of countries in alphabetical order using Angularjs.
Somewhat like A : America , Australia B: Brazil, Bhutan ...
The list is coming from a table named countries. I tried to apply angularjs filter on the first alphabet of the country name but failed. Do I have to create a custom filter for it?
Ok I am going to answer my own question finally got it working.
I was pulling a list of countries from a postgres db in the following format:
{"alpha2":"ao","alpha3":"ago","numeric":"024","country":"Angola"}
I wanted to split the list of countries in alphabetical order like this :
[Example] http://infoplease.com/countries.html#ALPHA-A
I finally got it working by writing a custom filter:
angular.module('countryFilter', []).filter('cfilter', function() {
return function(input,x) {
var groups = [];
for(var i = 0; i < input.length; i++) {
if (input[i].country.substring(0,1) == x)
groups.push(input[i]);
} return groups; }
});
and using it as :
ng-repeat="data in countries | cfilter:'A'
{{data.country}}
Do let me know if there is any better way for doing this...
This is another possible solution without the use of a filter
http://www.bennadel.com/blog/2456-Grouping-Nested-ngRepeat-Lists-In-AngularJS.htm
He creates a new array with a label and the data. The advantage is that in the template you don't have to name all the possible letters.
For my own I take the first letter of the client from the object and store that in the label. In that way I only get the letters I used.
In customer I have stored an array with objects.
for(var i = 0; i < customers.length; i++){
var customer = customers[i];
if(customer[ 'title' ].substring(0,1) !== groupValue){
var group = {
label : customer[ 'title' ].substring(0,1),
customers : []
};
groupValue = customer.title.substring(0,1);
groups.push( group );
};
group.customers.push( customer );
};
Sort Item List is a jQuery plugin that creates iOS-style sticky headers similar to those seen in the Music and Contacts apps on Apple devices
check link :
http://www.codingprogrammer.com/tutorialdemo/jquery-tutorial/sort-items-alphabetically-jquery-2/
I'd like to be able to search model attributes contained within a backbonejs collection. This is how I do it now...
wherePartial: function(attrs) {
// this method is really only tolerant of string values. you can't do partial
// matches on objects, but you can compare a list of strings. If you send it a list
// of values; attrs={keyA:[1,2,3],keyB:1}, etc the code will loop through the entire
// attrs obj and look for a match. strings are partially matched and if a list is found
// it's expected that it contains a list of string values. The string values should be considered
// to be like an OR operation in a query. Non-list items are like an AND.
if (_.isEmpty(attrs)) return [];
var matchFound = false;
return this.filter(function(model) {
// this is in the outer for loop so that a function isn't created on each iteration
function listComparator(value, index, list){
return model.get(key).toLowerCase().indexOf(value.toLowerCase()) >= 0;
}
for (var key in attrs) {
if (_.isArray(attrs[key])){
matchFound = _.any(attrs[key],listComparator);
if (matchFound !== true) return false;
} else {
matchFound = model.get(key).toLowerCase().indexOf(attrs[key].toLowerCase()) >= 0;
if (matchFound === false) return false;
}
}
return true;
});
}
Assume "C" is an instantiated collection, this is how I use it:
name:joe (nickname:joe the man nickname:joe cool nickname:joey)
is typed into a textbox and converted into this:
C.wherePartial({name:"joe",nicknames:["joe the man","joe cool","joey"]})
The above method returns all models that have the name joe and within that scope, any of the models that have the name joe and any of the nicknames. It works well for what I use it for. However, I'd really like to make a search that doesn't require the key:value pattern. I'd like to do this in a search box like when using a search engine on the web. I thought about just looking at every attribute on each model, but that takes awhile when you have a large collection (160k+ models).
Has anyone come across a need like this in the past? If so, how did you solve it? I'd like to keep the search contained on the client and not use any ajax calls to the backend. The reason for this is that the entire collection is already loaded on the client.
I thought of a way to do it. Serialize the attributes to a string during model instantiation. Listen for updates and update the serialization.
serializeAttr: function(){
this.serializedAttr = "";
var self = this;
_.each(this.toJSON(),function(value, key, list){
self.serializedAttr += value;
});
}
Then I can do simple searches on that cached value:
cc.serializedAttr.toLowerCase().indexOf("joe") >= 0