I'm trying to make a generic code to make it in a simple way for next level purpose. Please find the commented code which I've made. But, its not working.
var app = angular.module('myApp', []);
app.factory('mainFactory',function($http){
return {
getData: function() {
return $http.get("data.json");
}
};
});
app.controller('mainCtrl', function($scope,$http,mainFactory){
var data = mainFactory.getData();
if(angular.isDefined(data)) {
data.success(function(d,s){
// I want this commented out code for the four lines defined below.
/*var a = [{name:"imagesArray"},{name:"taskArray"},{name:"courseArray"},{name:"newsArray"}];
for(var i = 0; i < a.length; i++) {
$scope.a[i].name = d.a[i].name ? d.a[i].name : [];
}*/
// I dont want this number of lines.
$scope.imagesArray = d.imagesArray ? d.imagesArray : [];
$scope.taskArray = d.taskArray ? d.taskArray : [];
$scope.courseArray = d.courseArray ? d.courseArray : [];
$scope.newsArray = d.newsArray ? d.newsArray : [];
});
}
});
If it can be simplified further, please let me know
You can use this for better way to define scope property, edit your code like below:
data.success(function(d,s){
var keyCollection = ["imagesArray","taskArray","courseArray","newsArray"];
keyCollection.forEach(function(key){
$scope[key] = d[key];
});
});
or if your project are also using lodash(or underscore).You can simply do this(just further , don't import lodash or underscore just because this one, no need cost):
// outside, create advance function
var advancePick = _.partialRight(_.pick, "imagesArray", "taskArray", "courseArray", "newsArray");
data.success(function(d,s){
// just beauty like this
_.extend($scope, advancePick(d));
});
Change $scope.a[i].name = d.a[i].name ? d.a[i].name : []; to
$scope[a[i].name] = d[a[i].name] || [];
In Javascript, you can access properties two ways :
1)
item.property
2)
item["property"]
Thomas already gave you the right answer.
If you want to simplify it further, you can get rid of the definition of your "var a" array by making an object. Then you can enumerate each public property using :
for(var propertyName in yourObject) {
// propertyName is is the name of each property
// you can get the value using: yourObject[propertyName ]
}
Happy coding!
var a = ["imagesArray","taskArray","courseArray","newsArray"];
for(var i = 0; i < a.length; i++) {
$scope[a[i]] = d[a[i]] ? d[a[i]] : [];
}
with the name version
var a = [{name:"imagesArray"},{name:"taskArray"},{name:"courseArray"},{name:"newsArray"}];
for(var i = 0; i < a.length; i++) {
$scope[a[i].name] = d[a[i].name] ? d[a[i].name] : [];
}
A last solution and the shortest most of all!
angular.merge($scope, d);
EDIT : this will work only if d is properly initialized before.
Other simplifications not related to those 4 lines:
you don't need $http injected into your controller, and you don't
need to test the result of the call to getData(): it returns a
promise, take that as given.
Also use .then(...) rather than the deprecated .success(...).
You
might however want to add .catch(...) onto the promise to handle or
at least log errors, but if just to log errors you can put that inside .getData() and keep the controller short.
Here's how those changes might look:
var app = angular.module('myApp', []);
app.factory('mainFactory',function($http, $log){
return {
getData: function() {
return $http.get("data.json")
.catch(function (e) { $log.error(e); });
}
};
});
app.controller('mainCtrl', function($scope,mainFactory){
mainFactory.getData()
.then(function(d){
// choose one of the other answers for the code here...
var keyCollection = ["imagesArray","taskArray","courseArray","newsArray"];
keyCollection.forEach(function(key){
$scope[key] = d[key];
});
});
});
Related
I've searched the questions here and on Google and I find answers, but they don't seem to work in my code. I want to add a new PhotoIndex property to a JSON object in AngularJS. I have the code below which works (the photos appear), but doesn't have the PhotoIndex property:
$scope.GetImagesOnBar = function ()
{
var photos = $scope.$parent.Photos;
return photos;
};
When I try to add the PhotoIndex property to the JSON array object named photos, it breaks the code and the photos no longer appear. Can you tell me why?
$scope.GetImagesOnBar = function ()
{
var photos = $scope.$parent.Photos;
var index = 0;
for (var i = $scope.ImageFirst; i <= $scope.ImageLast; i++)
{
photos[i].PhotoIndex = index;
index = index + 1;
}
return photos;
};
OK, thanks for the comments. I checked the console as suggested and saw the error "$scope.$parent.Photos[i] is undefined". I don't know why, but I decide to try angular.foreach and that worked. See the solution below.
$scope.GetImagesOnBar = function ()
{
var index = 0;
angular.forEach($scope.$parent.Photos, function (photo)
{
photo.PhotoIndex = index;
index = index + 1;
});
return $scope.$parent.Photos;
};
Here is my object:
$scope.info = [];
$scope.info = [{"name":"kanye","size":"","folder":"Folder"},{"name":"west","size":"","folder":"Folder"}]
$scope.infoObj = $scope.info.name;
console.log($scope.infoObj);
This return me Undefined. The response should be like this:
[{"name":kanye},{"name":west}]
But how to access the specific properties from a multiple object using angularJS or jquery/js?
This should solve the problem:
$scope.infoObj = $scope.info.map(function(obj){
var x = {};
x['name'] = obj['name'];
return x;
})
for ES6, it can be simplified to:
$scope.infoObj = $scope.info.map(x => ({name:x['name']}))
You can actually do a little bit of refactoring to make your code a little cleaner and more readable. Instead of setting your info value twice, set it once, and add the objects in each line after.
Like this:
$scope.info = [];
$scope.info.push({
"name":"kanye",
"size":"",
"folder":"Folder"
});
$scope.info.push({
"name":"west",
"size":"",
"folder":"Folder"
});
See how clean that is? Now it should be fairly obvious that info is an Array of objects, so doing $scope.info.name won't work. What I would recommend is creating a lookup function that can help grab a list based on the key you provide it.
Something like this:
function lookup(key) {
var result = [];
for (var i = 0; i < $scope.info.length; i++) {
var object = {};
object[key] = $scope.info[i][key];
result.push(object);
}
return result;
}
And then call it like this:
$scope.infoObj = lookup('name');
console.log($scope.infoObj);
I am trying to implement a solution to sort a table by clicking its headers, using AngularJS.
I found a good example after doing a Google search: https://scotch.io/tutorials/sort-and-filter-a-table-using-angular
I am able to see the up and down arrows, but the table does not sort when I click them.
I think the problem resides in how the JSON object is formatted in my situation. I have not been able to figure it out, and I am hoping that with the information that I am providing on this post, I can get some help to understand what I am doing incorrectly.
Here is a copy of the JavaScript:
(function (define, angular) {
'use strict';
define(function () {
var opportunityController = function ($scope, Metadata, Factory) {
var vm = this;
//set the default sort type
vm.sortType = 'Products';
//set the default sort order
vm.sortReverse = false;
Factory.Data(caller.sp, caller.filter).then(function (payload) {
var data = angular.fromJson(payload.data).Table;
ProcessData(data);
});
function ProcessData(data) {
if (angular.isDefined(data)) {
var counter = 0;
vm.products = [];
vm.productsSet = FindByAsObjectArray(function (x) {
return (x.TypeName == "Product");
}, data);
for (var index = 0, length = vm.productsSet.length; index < length; index++) {
vm.products[index] = {
data: vm.productsSet[index]
};
}
}
}
};
return ['$scope','Metadata','Factory',opportunityController];
});
})(define, angular);
I got it to work, final version: https://jsfiddle.net/itortu/nhhppf53/
Many thanks.
You are using controllerAs
ng-controller="Company:OpportunityController as opportunity"
therefor you have to reference sortType and sortReverse in your ng-click like so:
ng-click="opportunity.sortType = 'Products'; opportunity.sortReverse = !opportunity.sortReverse"
In Angular, I have in scope a object which returns lots of objects. Each has an ID (this is stored in a flat file so no DB, and I seem to not be able to user ng-resource)
In my controller:
$scope.fish = [
{category:'freshwater', id:'1', name: 'trout', more:'false'},
{category:'freshwater', id:'2', name:'bass', more:'false'}
];
In my view I have additional information about the fish hidden by default with the ng-show more, but when I click the simple show more tab, I would like to call the function showdetails(fish.fish_id).
My function would look something like:
$scope.showdetails = function(fish_id) {
var fish = $scope.fish.get({id: fish_id});
fish.more = true;
}
Now in the the view the more details shows up. However after searching through the documentation I can't figure out how to search that fish array.
So how do I query the array? And in console how do I call debugger so that I have the $scope object to play with?
You can use the existing $filter service. I updated the fiddle above http://jsfiddle.net/gbW8Z/12/
$scope.showdetails = function(fish_id) {
var found = $filter('filter')($scope.fish, {id: fish_id}, true);
if (found.length) {
$scope.selected = JSON.stringify(found[0]);
} else {
$scope.selected = 'Not found';
}
}
Angular documentation is here http://docs.angularjs.org/api/ng.filter:filter
I know if that can help you a bit.
Here is something I tried to simulate for you.
Checkout the jsFiddle ;)
http://jsfiddle.net/migontech/gbW8Z/5/
Created a filter that you also can use in 'ng-repeat'
app.filter('getById', function() {
return function(input, id) {
var i=0, len=input.length;
for (; i<len; i++) {
if (+input[i].id == +id) {
return input[i];
}
}
return null;
}
});
Usage in controller:
app.controller('SomeController', ['$scope', '$filter', function($scope, $filter) {
$scope.fish = [{category:'freshwater', id:'1', name: 'trout', more:'false'}, {category:'freshwater', id:'2', name:'bass', more:'false'}]
$scope.showdetails = function(fish_id){
var found = $filter('getById')($scope.fish, fish_id);
console.log(found);
$scope.selected = JSON.stringify(found);
}
}]);
If there are any questions just let me know.
To add to #migontech's answer and also his address his comment that you could "probably make it more generic", here's a way to do it. The below will allow you to search by any property:
.filter('getByProperty', function() {
return function(propertyName, propertyValue, collection) {
var i=0, len=collection.length;
for (; i<len; i++) {
if (collection[i][propertyName] == +propertyValue) {
return collection[i];
}
}
return null;
}
});
The call to filter would then become:
var found = $filter('getByProperty')('id', fish_id, $scope.fish);
Note, I removed the unary(+) operator to allow for string-based matches...
A dirty and easy solution could look like
$scope.showdetails = function(fish_id) {
angular.forEach($scope.fish, function(fish, key) {
fish.more = fish.id == fish_id;
});
};
Angularjs already has filter option to do this ,
https://docs.angularjs.org/api/ng/filter/filter
Your solutions are correct but unnecessary complicated. You can use pure javascript filter function. This is your model:
$scope.fishes = [{category:'freshwater', id:'1', name: 'trout', more:'false'}, {category:'freshwater', id:'2', name:'bass', more:'false'}];
And this is your function:
$scope.showdetails = function(fish_id){
var found = $scope.fishes.filter({id : fish_id});
return found;
};
You can also use expression:
$scope.showdetails = function(fish_id){
var found = $scope.fishes.filter(function(fish){ return fish.id === fish_id });
return found;
};
More about this function: LINK
Saw this thread but I wanted to search for IDs that did not match my search. Code to do that:
found = $filter('filter')($scope.fish, {id: '!fish_id'}, false);
I'm trying to translate a PHP class into JavaScript. The only thing I'm having trouble with is getting an item out of an array variable. I've created a simple jsfiddle here. I cannot figure out why it won't work.
(EDIT: I updated this code to better reflect what I'm doing. Sorry for the previous mistake.)
function tattooEightBall() {
this.subjects = ['a bear', 'a tiger', 'a sailor'];
this.prediction = make_prediction();
var that = this;
function array_random_pick(somearray) {
//return array[array_rand(array)];
var length = somearray.length;
var random = somearray[Math.floor(Math.random()*somearray.length)];
return random;
}
function make_prediction() {
var prediction = array_random_pick(this.subjects);
return prediction;
}
}
var test = tattooEightBall();
document.write(test.prediction);
Works fine here, you are simple not calling
classname();
After you define the function.
Update
When you make a call to *make_prediction* , this will not be in scope. You are right on the money creating a that variable, use it on *make_prediction* :
var that = this;
this.prediction = make_prediction();
function make_prediction() {
var prediction = ''; //initialize it
prediction = prediction + array_random_pick(that.subjects);
return prediction;
}
You can see a working version here: http://jsfiddle.net/zKcpC/
This is actually pretty complex and I believe someone with more experience in Javascript may be able to clarify the situation.
Edit2: Douglas Crockfords explains it with these words:
By convention, we make a private that variable. This is used to make
the object available to the private methods. This is a workaround for
an error in the ECMAScript Language Specification which causes this to
be set incorrectly for inner functions.
To see the complete article head to: http://javascript.crockford.com/private.html
You never call classname. Seems to be working fine.
Works for me:
(function classname() {
this.list = [];
this.list[0] = "tiger";
this.list[1] = "lion";
this.list[2] = "bear";
function pickone(somearray) {
var length = somearray.length;
var random = somearray[Math.floor(Math.random()*length)];
return random;
}
var random_item = pickone(this.list);
document.write(random_item);
}());
Were you actually calling the classname function? Note I wrapped your code block in:
([your_code]());
I'm not sure what you're trying to accomplish exactly with the class structure you were using so I made some guesses, but this code works by creating a classname object that has instance data and a pickone method:
function classname() {
this.list = [];
this.list[0] = "tiger";
this.list[1] = "lion";
this.list[2] = "bear";
this.pickone = function() {
var length = this.list.length;
var random = this.list[Math.floor(Math.random()*length)];
return random;
}
}
var cls = new classname();
var random = cls.pickone();
You can play with it interactively here: http://jsfiddle.net/jfriend00/ReL2h/.
It's working fine for me: http://jsfiddle.net/YznSE/6/ You just didn't call classname(). If you don't call it, nothing will happen ;)
Make it into a self-executing function like this:
(function classname() {
this.list = [];
this.list[0] = "tiger";
this.list[1] = "lion";
this.list[2] = "bear";
function pickone(somearray) {
var length = somearray.length; //<---WHY ISN'T THIS DEFINED??
var random = somearray[Math.floor(Math.random() * length)];
return random;
}
var random_item = pickone(this.list);
document.write(random_item);
})();
var test = tattooEightBall();
document.write(test.prediction);
Should be:
var test = new tattooEightBall(); //forgot new keyword to create object
document.write(test.prediction()); // forgot parens to fire method
and:
this.prediction = make_prediction();
Should be:
this.prediction = make_prediction;