I want to parse the JSON response of Country & State from below mentioned URL.
https://gist.githubusercontent.com/mayurah/5f4a6b18b1aa8c26910f/raw/countriesToCities.json
{
"China": [
"Guangzhou",
"Fuzhou",
"Beijing",
"Baotou",
"Hohhot",
"Guiyang",
"Yinchuan",
"Nanjing",
"Changzhou",
"Chuzhou",
"Hefei",
"Jinan",
"Qingdao",
"Harbin",
"Zhaodong",
"Taiyuan",
"Xi'an",
.
.
.
}
]
I want the result as,
Guangzhou, China
Taiyuan, China
I am using AngularJS, Following is a piece of code of my controllers.js file.
var
apiUrl = {
countryStateList: 'https://gist.githubusercontent.com/mayurah/5f4a6b18b1aa8c26910f/raw/countriesToCities.json'
};
countryData.controller('countryDataCtrl', ['$scope', '$http', function($scope, $http) {
$http.get(apiUrl.countryStateList).success(function(data) {
// console.log(data);
$scope.countryStateList = data;
});
}]);
And, in my HTML file, code is something like this,
<ul ng-repeat="country in countryStateList">
<li>{{ STATE_NAME, COUNTRY_NAME }}</li>
</ul>
STATE_NAME & COUNTRY_NAME are just for in display information. Both must be replaced with Angular code.
The problem is JSON element names are itself country names. Can someone tell me how to parse the same in AngularJS/Javascript.
You could start by parsing the whole JSON:
var jsonObject = JSON.parse(RAW_JSON_STING);
var newJsonObject = [];
// Loop through it
for (var interator in jsonObject)
{
for (var it = 0; it < iterator.length; it++)
{
newJsonObject.push(iterator[it] + ", " + iterator);
}
}
No guarantee the code above will work as intended.
Ng-repeat will not be useful in your case. This would be possible using directive.
<datalist id="stateCountry">
<custom-datalist-option data-array="countryStateList"></custom-datalist-option>
</datalist>
Link a directive function and create an option using using it.
Here is the Update Fiddle
Hope this will help you.
Related
I am working on a web app where non-profit organizations can create a profile and be easily searchable by various parameters. In the "create and organization" form, I have a nested array where the organization can add donations that they need. The array is storing ok (I can add multiple donations), however when I try to display it using ng-repeat, nothing renders. When I don't use the ng-repeat and just display via {{ ctrl.organization.donations }} the information shows up with brackets and quotation marks.
Here is the code that I use to add the donations (via the newOrganization controller):
function NewOrganizationController(OrganizationService, CategoryService, $stateParams, $state, $http, Auth){
var ctrl = this;
CategoryService.getCategories().then(function(resp) {
ctrl.categories = resp.data;
});
ctrl.donations = [{text: ''}];
Auth.currentUser().then(function(user) {
ctrl.user = user;
})
ctrl.addNewDonation = function() {
var newDonation = ctrl.donations.length+1;
ctrl.donations.push({text: ''});
};
ctrl.removeDonation = function() {
var lastItem = ctrl.donations.length-1;
ctrl.donations.splice(lastItem);
};
ctrl.addOrganization = function() {
var donations = this.donations;
var allDonations = [];
for (var key in donations) {
if (donations.hasOwnProperty(key)) {
var donation = donations[key].text;
allDonations.push(donation);
}
}
var data = {
name: ctrl.organization.name,
description: ctrl.organization.description,
address: ctrl.organization.address,
donations: allDonations.join("/r/n"),
category_id: this.category.id
};
OrganizationService.createOrganization(data);
$state.go('home.organizations');
};
}
angular
.module('app')
.controller('NewOrganizationController', NewOrganizationController);
Here is the code that I am using to display the array on my show page (this is what shows up with brackets, i.e. donations needed: ["food", "clothing"]):
<h5>{{ ctrl.organization.donations }}</h5>
This is the ng-repeat code that is not rendering anything to the page:
<li class="list-group-item" ng-repeat="donation in donations track by $index">
{{ donation }}
</li>
I've tried to use .join(', ') within the {{donation}} brackets, but this isn't recognized as a function.
edit: After taking AJ's suggestion here is a screenshot of what appears...anyone know how to fix this?
seems that my array is showing up in table form, with each row containing one character
Any help would be greatly appreciated. Here is a link to the github repo in case you want to look at anything else or get a bigger picture.
You need to use the same variable name that works in the h5
<li class="list-group-item" ng-repeat="donation in ctrl.organization.donations track by $index">
{{ donation }}
</li>
I'm not sure it is possible to use ng-init and ng-repeat in the same div. I need it to select from the database all comments that have an id of 6.
I'm calling the code here and displaying an array:
< div ng-init="getComments('6')" ng-repeat="comment in comments">{{ comment.message }}< /div>
And this is what the function looks like in the angular file:
$scope.getComments = function(statusid) {
Comment.get(statusid)
.success(function(data) {
$scope.comments = data;
$scope.loading = false;
});
};
And calling the API here:
return {
// get all the comments
get : function(statusid) {
return $http.get('/api/comments' + statusid);
},
Am I missing something simple? I did not include the PHP files as that seems to all be working fine.
In a template, I have:
<div ng-controller="projectListController as projects" class="pull-right" id="projectListDropDown">
<select ui-select2 id="projectListDD" placeholder="All" class="width240" ng-model="projects.projectSelection">
<option value=""></option>
<option ng-repeat="item in projects.projectList" value="{{item.WebsiteName}}">{{item.WebsiteName}}</option>
</select>
</div>
I want to populate the dropdown list from projectList below:
app.controller('projectListController', ['$rootScope', '$scope', '$log', 'abstractDataFactory', 'customUIFunctions', 'globalContainer',
function ($rootScope, $scope, $log, abstractDataFactory, customUIFunctions, globalContainer) {
dashboardGlobals = this.dashboardGlobals = globalContainer.dashboardGlobals;
var dataFactory = new abstractDataFactory("/odata/ProjectList");
var projectController = new abstractDataFactory("/Projects/ChangeCurrentProject") // load up projectDashboardDTO
this.selectProjectPlaceholder = "Loading Projects . . .";
this.filterItems = [
{ id: 1, text: 'Item1' },
{ id: 2, text: 'Item2' },
{ id: 3, text: 'Item3' },
{ id: 4, text: 'Item4' }
];
this.projectList = [];
// TODO; keep a global list of projects
// Get a list of current projects
dataFactory.getList("") // no parameters
.success(function (result) {
this.projectList = result.value; //<- array of objects is returned
dashboardGlobals.projectList = result.value;
this.selectProjectPlaceholder = "Select a project . . . "
$("#projectListSelection").select2({ width: '240' });
})
.error(function (error) {
customUIFunctions.showError("Data Error - Unable to Load Project List"); // use default error message
console.log("data error");
});
I have confirmed that there is data in result.value but the list remains blank.
However, when I use projects.filterItems in the ng-repeat, (along with id and text field names) the list is populated.
I also want the changed value to be globally accessible in Angular, so I injected my own globalContainer service into this controller, and whenever the page is refreshed, I want to ensure the selected value remains consistent, rather than resetting.
-- UPDATE --
The problem seems to be in the .success area, this.projectList is undefined. If I do var projectList = this.projectList = [] no error, but this doesn't seem right.
So the issue is with trying to define the variables after the fact, and using Controller as....
How can I get this working?
After reading something about half way down the page, here, and a bit more further understanding about the difference between $scope and this, in how they work in .success, I declared vm as a top-level this:
var vm = this;
vm.dashboardGlobals = globalContainer.dashboardGlobals;
var dataFactory = new abstractDataFactory("/odata/ProjectList");
var projectController = new abstractDataFactory("/Projects/ChangeCurrentProject") // load up projectDashboardDTO
vm.projectList = [];
.
.
.
dataFactory.getList("") // no parameters
.success(function (result) {
vm.projectList = result.value;
vm.dashboardGlobals.projectList = result.value;
vm.selectProjectPlaceholder = "Select a project . . . "
When I do a search in my application, I want to wrap the matching characters in the results with bold tags so you can see the matches.
So the results view looks like:
<ul class="search-results ng-hide" ng-show="(results | filter: filterQuery).length > 0">
<li ng-repeat="result in results | filter:filterQuery">
<h3><a ui-sref="{{result.state}}">{{result.name}}</a></h3>
<p>{{result.snippet}}</p>
</li>
</ul>
And the controller:
myApp.controller('SearchCtrl', function($rootScope, $scope, $state, Result, $location, $filter) {
$scope.query = ($state.includes('search') ? $location.search()['q'] : '');
$scope.filterQuery = ($state.includes('search') ? $location.search()['q'] : '');
$scope.results = [];
$scope.queryChanged = function () {
$scope.filterQuery = $scope.query;
if($scope.query){
$state.go('search', {'q': $scope.query} );
} else {
$location.search('q', null);
}
}
if($scope.query){
$scope.results = Result.query();
} else {
$location.search('q', null);
}
});
So I need to wrap tags around the result.name and result.snippet when it matches the filterQuery.
Something like (bits of this were copied from a PHP version I've done in the past, hence the mismatched syntax):
var keys = $scope.filterQuery.split(" ");
result.snippet.replace('/('.implode('|', keys) .')/iu', '<b>\0</b>');
But where would this go?
Create a search-result directive to wrap each search result, where name needs to be set as bold:
<search-result result="result" name="name" ></search-result>
With the following template:
directive.template: 'prefix text' + '<B>' + attrs.name + </B> + ' suffix text';
There's a few ways you could do this, mostly using filters.
You could write your own filter, that would take the string in the search, find it in the content that you are searching, and then add the tags around it and send it back.
Or, you can use one of the many plugins out there that does this.
Heres a question that talks about it
Angular UI Highlight
Some of my wording may be off especially regarding angular/js terminology (controller, service, factory, etc), but hopefully it is still understandable. Also, this question has multiple parts, which made it difficult to ask in one line.
I have 3 files: newRegistration.html, Registration.js, and addressVerification.js.
In newRegistration.html, there is a form where the user inputs his/her email, phone, mailing address, and other things and then clicks "next". Upon clicking next, Registration.js (a controller?) is triggered (?).
newRegistration.html
In the following snippet is the ng-repeat that I'd like to update with new data from addressVerification.js.
<div id="dialog-form" title="CHOOSE THE CORRECT ADDRESS">
<ul>
<li ng-repeat="for item in [not sure what to put here because of two js files]">
</li>
</ul>
</div>
Registration.js
The controller for the template that contains the ng-repeat mentioned above.
The top line looks like this:
angular.module('appname')
.controller('RegistrationCtrl', function ($scope, $http, cacheStore, countryStates, birthYear, $anchorScroll, errorMessages, addressVerification, UtilsFactory)
And this is a line that may be relevant:
addressVerification.verify(user).then(function (userObj)
addressVerification.js
Uses the Smartystreets API to correct/suggest the mailing address.
I can't figure out how to pass variables from this module to Registration.js (where the scope variable [?] is) in order to populate the ng-repeat in newRegistration.html.
angular.module('appname').factory('addressVerification', function($q, userIdentity, $http, smartyToken) {
"use strict";
return {
verify: function(obj) {
var deferred = $q.defer(),
street2QS = "";
if (obj.address2 || obj.address2 !== "") {
street2QS = "&street2=" + encodeURIComponent(obj.address2);
}
$http.jsonp("https://api.smartystreets.com/street-address?street=" + encodeURIComponent(obj.address1)
+ street2QS
+ "&city=" + encodeURIComponent(obj.city)
+ "&state=" + encodeURIComponent(obj.state)
+ "&zipcode=" + encodeURIComponent(obj.zip)
+ "&source=website&auth-token="+ smartyToken.get() + "&candidates=5&callback=JSON_CALLBACK")
.success(function (response) {
var metaData,
components;
if (response && response.length === 1) {
metaData = response[0].metadata || {};
components = response[0].components || {};
angular.extend(obj, {
"address1": [
components.primary_number,
components.street_name,
components.street_suffix
].join(" "),
"address2": [
components.secondary_designator,
components.secondary_number
].join(" "),
"city": components.city_name,
"county_name": metaData.county_name,
"county_fips": metaData.county_fips,
"state": components.state_abbreviation,
"latitude": metaData.latitude,
"longitude": metaData.longitude,
"plus4_code": components.plus4_code,
"zip": components.zipcode
});
deferred.resolve(obj);
} else {
deferred.reject(false);
}
}).error( function() {
deferred.reject(false);
});
return deferred.promise;
}
};
});
I'm pretty clueless right now. I think I've given all of the necessary details. I wish I knew where to start. I read all about deferred objects, ng-repeat, and controllers, but it's confusing me.
Any help appreciated.
You're injecting addressVerification into RegistrationCtrl. The value of addressVerification that is injected into the RegistrationCtrl is the value returned by executing the function you're defining here:
angular.module('appname')
.factory('addressVerification', function($q, userIdentity, $http, smartyToken)
Therefore you can access the stuff that's happening inside of the addressVerification.js file in the RegistrationCtrl.js file by adding methods to whatever it is you're returning in that function.
Once you have your data in RegistrationCtrl, you can access it from the view by appending data to the scope inside of RegistrationCtrl. Example:
This would go in RegistrationCtrl.js:
$scope.someItems = [1, 2, 3, 4];
This would go in the view:
<li ng-repeat="item in someItems">{{item}}</li>
The way that I have implemented this is by exposing methods of a factory that allow the controllers (and the controller's view(s)) that depend on it to store values within the same factory.
For example, in the following code, the setCurrent method of the customers factory stores a value, current in the factory. Because factories are singletons, will persist in the application. Even after the user's click on the <a> (in the following example) and they are taken to href="/", the value that was stored in customers.current will be accessible to the "/" route's controller if the same factory is a dependency for both controllers.
Template
<ul>
<li>{{customers.current.name}}</li>
<li
ng-repeat="customer in customers.all"
>
<a
class="action name"
ng-click="customers.setCurrent(customer)"
href="/"
>
{{customer.name}}
</a>
</li>
</ul>
Controller
angular
.module('CtrlCustomerList', [
'CollectionCustomers',
])
.controller('CtrlCustomerList', function($scope, CollectionCustomers) {
$scope.customers = CollectionCustomers;
});
Factory
angular
.module('CollectionCustomers', [
])
.factory("CollectionCustomers", function(Restangular, ModelCustomer, $location) {
return {
all : [],
current : null,
setCurrent : function() {
// Affect this.current
}
}
});