Referring from the below code. i use catcomplete from jQuery ui and i want to get the country list from each catagory to show up when seaching but i get undefined what i do wrong ?
This my object array:
24:category:"Afrika"
country:1:{label: "Namibia"}
2:{label: "Sydafrika"}
3:{label: "Tanzania"}
4:{label: "Madagaskar"}
25:category:"Asien"
country:1:{label: "Private: Södra Indien"}
2:{label: "Indonesien"}
3:{label: "Filippinerna"}
4:{label: "Indien"}
5:{label: "Thailand"}
This my function:
$('#autocomplete').catcomplete({
source: function (request, response) {
//data :: JSON list defined
response($.map(TourArea, function (value, key) {
return {
category: value.category,
label: value.country.label,
}
}));
},
});
Result is: country array get undefined
Result
Now i find out and it work. all i need is just merge all object to be in one.
How to make multi id array object to all in one
let newData = Object.values(data).map(v => {
let x = [];
for (let k in v) x.push(v[k]);
return x;
}).reduce((c, v) => {
c = c.concat(v);
return c;
}, []);
And autocomplete function:
$('#autocomplete').catcomplete({
source: newData,
});
Done all working fine.
Related
I need to create a javascript object using values stored in an array. Every value should be a new key inside the previous one. What would be the best approach to achieve this?
var option = ['level_1','level_2','level_3','level_4'];
$.each( option, function( key, value ) {
// ....
});
// I'm trying to get this result
var result = {
'level_1': {
'level_2': {
'level_3': {
'level_4':{}
}
}
}
}
You can use reduceRight for this, with the ES6 computed property name syntax.
const option = ['level_1','level_2','level_3','level_4'];
const obj = option.reduceRight( (acc, lvl) => ({ [lvl]: acc }), {});
console.log(obj);
In traditional function syntax it would be:
const obj = option.reduceRight(function (acc, lvl) {
return { [lvl]: acc };
}, {});
You have to keep track of where to put the next key. So, create a variable and initially set it to result, then on each pass through the array, move where that variable points to.
var option = ['level_1','level_2','level_3','level_4'];
var result = {};
var nextKeyGoesHere = result;
option.forEach( function( value ) {
nextKeyGoesHere[value] = {};
nextKeyGoesHere = nextKeyGoesHere[value];
});
console.log(result);
Can use Array#reduce()
var option = ['level_1','level_2','level_3','level_4'];
var res = {};
option.reduce((o, key) => (o[key] = {} , o[key]), res)
console.log(res)
you can use any of the other answers that use Array#reduce, however, if you'd like a recursive version here it is:
function _makeTree(arr, index, subtree){
if(index < arr.length){
subtree[arr[index]] = {};
return _makeTree(arr, index+1, subtree[arr[index]])
}
else return;
}
function makeTree(arr){
var tree = {};
_makeTree(arr, 0, tree)
return tree;
}
var arr = ['level_1','level_2','level_3','level_4'];
console.log(makeTree(arr));
I'm trying to create a list of data items that have first been filtered by value, then sorted by descending value, then sliced to only show the top 5 items. I'm using an Angular factory to return these values to my controller, so that I can display the values in the DOM.
I've been successful in sorting and slicing the data, but I'm running into problems when I run dataHandler.filter. I get the error: 'Cannot read property 'slice' of undefined'.
Here is my controller where I try to return a new list after running each of these functions:
Controller
getData().then(function(data) {
function updateChart() {
// get match value
var filterValue = inputService.primaryInputs[0]["value"];
// plug match value into filter ** should return only data items with matches
var filtered = dataHandler.filter(data, "Description", filterValue);
// sort by descending value "percent"
var sorted = dataHandler.sort.descending(filtered, "Percent");
// return top 5 results
var sliced = dataHandler.slice(sorted, 5);
$scope.barData = sliced;
}
updateChart();
});
I know that dataHandler.sort.descending and dataHandler.slice or working correctly, because I can use data as an argument in dataHandler.sort.descending and the list is returned perfectly. However, when I try to plug use filtered, I get 'Cannot read property 'slice' of undefined'.
Factory
app.factory('dataHandler', function ($rootScope) {
return {
filter: function(data, dataProp, input) {
data.filter(function(value, index, array) {
console.log(value[dataProp] == input);
return value[dataProp] == input;
});
},
sort: {
ascending: function (data, sortCriteria) {
if (data) {
data.sort(function (a, b) {
return a[sortCriteria] - b[sortCriteria];
});
};
return data;
},
descending: function (data, sortCriteria) {
if (data) {
data.sort(function (a, b) {
return b[sortCriteria] - a[sortCriteria];
});
};
return data;
}
},
slice: function (data, howMany) {
if (howMany) {
return data.slice(0, howMany);
} else {
return data;
}
}
};
Again - I want to use dataHandler.filter to return a new list with only the items whose Description values match the filterValue.
The reason it doesn't work is because you aren't returning anything in your dataHandler.filter function.
It should be:
filter: function(data, dataProp, input) {
return data.filter(function(value, index, array) {
console.log(value[dataProp] == input);
return value[dataProp] == input;
});
}
Remember that Array.prototype.filter does not work in place, like Array.prototype.reverse.
Even though this will work, I would suggest that you don't actually need a factory for these tasks. Filtering, slicing and sorting are very general purpose tasks and there is no need to wrap around the native implementation (unless you are polyfilling).
I would rewrite the entire factory as a service of reusable transform functions that can be used in a series of chained operations.
.service('Transform', function() {
// we will pass this to filter
this.propEquals = function(property, value) {
return function(data) {
return data[property] === value;
};
};
// we'll pass this to sort
this.sort = function(criteria, ascending) {
return function(a, b) {
return ascending?
a[criteria] - b[criteria] : b[criteria] - a[criteria];
};
};
})
Then your updateChart method becomes.
function updateChart() {
var filterValue = inputService.primaryInputs[0]["value"];
$scope.barData = data
.filter(Transform.propEquals("description", filterValue))
.sort(Transform.sort("Percent", false))
.slice(0, 5);
}
I'm refactoring some JS code to CoffeeScript, and having a problem with a function.
This is the JS that works:
$(".comformt_QA").change(function(){
var array = $(".comformt_QA").map(function() {
return $(this).val();
}).toArray();
$("[name='comfort_qualitative_assessment.global_comfort_index']").val(
calc_qualitative_assessment_array(array)
).change();
});
My goal is to use this snipplet as a function, and be able to call:
class_to_calc_qualitative_assessment_array(".comformt_QA", "[name='comfort_qualitative_assessment.global_comfort_index']");
Here's the CoffeeScript:
#class_to_calc_qualitative_assessment_array = (class_param, target) ->
array = []
$(class_param).change ->
array = $(class_param).map( ->
$(this).val()
)
$(target).val(calc_qualitative_assessment_array(array)).change()
array is always empty...
Thoughts?
If you compile your coffee code to Javascript this would be the result:
this.class_to_calc_qualitative_assessment_array = function(class_param, target) {
var array;
array = [];
$(class_param).change(function() {
return array = $(class_param).map(function() {
return $(this).val();
});
});
return $(target).val(calc_qualitative_assessment_array(array)).change();
};
Coffeescript transpiles the # to the this keyword in JS. Also you don't have returns within your function - this leads to coffeescript returning the last assigned value of the function.
Maybe this would be a working approach:
class_to_calc_qualitative_assessment_array = (class_param, target) ->
array = []
$(class_param).change ->
array = $(class_param).map( ->
$(#).val()
)
return
$(target).val(calc_qualitative_assessment_array(array)).change()
return
Transpiled this looks like this:
var class_to_calc_qualitative_assessment_array;
class_to_calc_qualitative_assessment_array = function(class_param, target) {
var array;
array = [];
$(class_param).change(function() {
array = $(class_param).map(function() {
return $(this).val();
});
});
$(target).val(calc_qualitative_assessment_array(array)).change();
};
I can't seem to get this right: I've got an array with categories (objects) and a post object:
var categories = $http.get('/api/categories').success(function (data) {
$scope.categories = data;
});
// The code below uses a Rails gem to transport data between the JS and Rails.
$scope.post = gon.post;
// Suffice to say the $scope.post is an object like so:
...
_id: Object { $oid="54f4706f6364653c7cb60000"}
_slugs: ["first-post"]
author_id: Object { $oid="54ef30d063646514c1000000"}
category_ids: [Object, Object]
...
As you can see the post object has a property category_ids which is an array whit all categories associated with this post. In my view (haml) I have the following:
%label
%input{"type" => "checkbox", "ng-model" => "cat.add", "ng-change" => "addCategory(cat)", "ng-checked" => "currentCat(cat)"} {{cat.name}}
As you can see, the ng-checked fires the currentCat() function:
$scope.currentCat = function (cat) {
for (var i = 0; i < cat.post_ids.length; i++){
if (cat.post_ids[i].$oid == $scope.post._id.$oid) {
return true;
}
}
};
The function above loops through the categories in the post (the category_ids property of the post object) and compares it with the parameter given. It works fine with existing categories. The problem appears when I dynamically add a new category and push it in the categories array:
$scope.addCatBtn = function () {
var category = $scope.cat;
$http.post('/api/categories', category).success(function (data) {
$scope.categories.push(data.category);
$scope.cat = '';
$scope.addCategory(data.category);
});
};
The new category does not appear 'checked' in the view. What am I missing?
Any thoughts would be appreciated.
EDIT: Adding addCategory function:
$scope.addCategory = function (cat) {
var found = false;
for (var i in $scope.post.category_ids) {
if (cat._id.$oid === $scope.post.category_ids[i].$oid) {
$scope.post.category_ids.splice(i, 1); // splice, not slice
found = true;
}
}
if (!found) { // add only if it wasn't found
$scope.post.category_ids.push(cat._id);
}
console.log($scope.post);
}
ngModel and ngChecked are not meant to be used together.
You should be fine to just use ngModel.
How could I get an array json of a json file with javascript and jquery
I was triyng with the next code, with it doesnt work:
var questions = [];
function getArray(){
$.getJSON('questions.json', function (json) {
for (var key in json) {
if (json.hasOwnProperty(key)) {
var item = json[key];
questions.push({
Category: item.Category
});
}
}
return questions;
})
}
this is the json file called: questions.json
{
"Biology":{
"Category":{
"cell":{
"question1":{
"que1":"What is the cell?"
},
"option1":{
"op1":"The cell is the basic structural and functional unit",
"op2":"is a fictional supervillain in Dragon Ball"
},
"answer1":"opt1"
}
}
},
"Astronomy":{
"Category":{
"Mars":{
"question1":{
"que1":"How many moons does Mars?"
},
"option1":{
"op1":"5",
"op2":"2"
},
"answer1":"opt2"
}
}
}
}
I want to get an array with this format {Biology:{Category:{cell:{question1....}}}}
$.getJSON is an asynchronous function, so returning something inside that function does nothing, as it's not in scope, or received yet. You should probably do something like:
function getArray(){
return $.getJSON('questions.json');
}
getArray().done(function(json) {
// now you can use json
var questions = [];
$.each(json, function(key, val) {
questions[key] = { Category: val.Category };
});
});
Your conditional within the for loop prevents anything from being added to your array. Instead, check if your json object has the property, then get the value and add it to your array. In other words:
if (questions.hasOwnProperty(key)) should be if (json.hasOwnProperty(key))
Also, you can't simply return the result of an AJAX call like that, because the method runs asynchronously. That return is actually applied to the inner success function callback, not getArray. You have to use a callback pattern in order to pass the data only once it has been received, and operate on it accordingly.
(Of course since the array is defined in the outer scope you wouldn't have to return it anyway, but if you attempted to use it before the AJAX method ended it would be empty.)
Assuming you are going to render it to the DOM using a method called renderJSON:
var questions = [];
function getArray(){
$.getJSON('questions.json', function (json) {
for (var key in json) {
if (json.hasOwnProperty(key)) {
var item = json[key];
questions.push({
Category: item.Category
});
}
}
renderJSON(questions);
});
}