Calling a method from multiple component - arrays

I have a method that makes http get request from a url, this method gets called from multiple components, each call is making the http request, so I have stored the result in an array to return the array on the second call and not make the http request again, but it is not returning the array, its making the http request again.
Here is my code:
export class ProductsService {
public currency: string = '';
public products: Product[];
// Initialize
constructor(private http: HttpClient, private toastrService: ToastrService) {
}
// Get Products
public getProducts(): Observable<Product[]> {
return this.getAllProducts();
}
private getAllProducts(): Observable<Product[]> {
if (this.products) {
return of(this.products);
} else {
return this.getIp().pipe(
switchMap(country => {
this.currency = this.getCurrency(country);
return this.http.get('http://localhost:8080/products/getAllProducts?currency=' + this.currency).pipe(
map((res: any) => {
this.products = res;
return this.products;
})
);
})
);
}
}
private getIp() {
return this.http.get<any>(('http://ip-api.com/json/?fields=countryCode')).pipe(
map(r => r.countryCode)
);
}
private getCurrency(country: string): string {
let currency;
if (country === 'JO') {
currency = 'JOD';
} else if (country === 'AE') {
currency = 'AED';
} else if (country === 'SA') {
currency = 'SAR';
} else if (country === 'GB') {
currency = 'GBP';
} else if (country === 'DE') {
currency = 'EUR';
} else if (country === 'KW') {
currency = 'KWD';
} else if (country === 'EG') {
currency = 'EGP';
} else {
currency = 'USD';
}
return currency;
}
}
what am I doing wrong here why the method is making the http request again after the first call, shouldn't the array be filled and returned?
Please note that the components are calling the method getProducts() in the ngOnInit()

You are returning the get which is an observable. Each time these methods are called they begin a new subscription to the endpoints.
public getProducts(): Observable<Product[]> {
return this.getAllProducts();
}
private getAllProducts(): Observable<Product[]> {
if (this.products) {
return of(this.products);
} else {
return this.getIp().pipe(
switchMap(country => {
this.currency = this.getCurrency(country);
return this.http.get('http:/ <== this is an observable
You need a service to sync this stuff.
I have an example service for simple state that I used to sync URL params for many components on StackBlitz that may help you.

Related

Use for of loop to iterate the array

Assignment task4: Add the listStudents() method
In this task, you will add a method to the Bootcamp class that lists all the registered students' names and emails.
Create a method in the Bootcamp class named listStudents().
In the method body:
Check if the this.students array is empty.
If so, console.log() the message:
No students are registered to the ${this.name} bootcamp.
Then return the boolean value of false.
Otherwise, console.log() the line:
The students registered in ${this.name} are:
Then iterate through the entire this.students array and console.log() the name and email of each student on one line for each student. See the Testing section below for an example of the expected output.
You can do this with the for...of loop.
Finally, return the boolean value of true.
Testing code:
const runTest = (bootcamp, student) => {
const attemptOne = bootcamp.registerStudent(student);
const attemptTwo = bootcamp.registerStudent(student);
const attemptThree = bootcamp.registerStudent(new Student("Babs Bunny"));
if ( attemptOne && !attemptTwo && !attemptThree) {
console.log("TASK 3: PASS");
}
bootcamp.registerStudent(new Student('Babs Bunny', 'babs#bunny.com'));
if (bootcamp.listStudents()) {
console.log("TASK 4: PASS 1/2");
}
bootcamp.students = [];
if (!bootcamp.listStudents()) {
console.log("TASK 4: PASS 2/2");
}
};
My code below does not work. Please help me review. Thanks
class Bootcamp {
constructor(name, level, students = []){
this.name = name;
this.level = level;
this.students = students;
}
registerStudent(studentToRegister){
if (!studentToRegister.name || !studentToRegister.email) {
console.log("Invalid name or email");
return false;
} else if(this.students.filter(s => s.email === studentToRegister.email).length) {
console.log("This email is already registered");
return false;
} else {
this.students.push(studentToRegister)
console.log(`Successful registration ${studentToRegister.name} ${Bootcamp.name}`)
return true;
}
}
listStudent(registerStudent){
if(this.students.length === 0)
{
console.log(`No students are registered to the ${this.name} bootcamp.`);
return false;
}
else
{
console.log(`The students registered in ${this.name} are:`);
for(const registerStudent of this.students)
{
console.log("Name:" + registerStudent[name] + "Email:" + registerStudent[email]);
return true;
}
}
}
}
listStudents() {
if (this.students.length == 0) {
console.log("No students are registered to the ${this.name} bootcamp");
return false;
} else {
console.log("The students registered in ${this.name} are:");
for (let student of this.students) {
console.log(`Name: ${student.name} Email: ${student.email}`);
}
return true;
}
}
}

How to return response to calling function in AngularJS?

I am calling this method testDataService, which is defined in the same JS file. This method returns a list which it gets from an API call. I want to set that value to model and return model object. but my return function is getting called before my API returns the response. How can i make sure return function will get called only after the above if block get the data from API.
getTestData(model) {
model.name = "practice";
model.value = 2;
// this if loop is calling an API and setting up data into model.
if(this.model.form.length>0 && this.model.form[0].entityName === 'test'){
let responseList;
this.testDataService(this.model).then(response => {
responseList = response;
model.class = responseList;
});
}
return this.model;
// this return function is getting called before the api returns its data. How can i make sure this return will get called only after the above if block get the data from API.
}
This is method definition
testDataService(model) {
let profileType = "test";
let profileId = "test_profile";
let configCategory = "test";
return this.referenceDataService.getTestData(profileType, profileId, configCategory);
}
You need to pass return statement from the callback, instead of placing it outside.
getTestData(model) {
model.name = "practice";
model.value = 2;
// this if loop is calling an API and setting up data into model.
if (this.model.form.length > 0 && this.model.form[0].entityName === 'test') {
this.testDataService(this.model).then(response => {
let responseList = response;
model.class = responseList;
return this.model;
}).then(response => {
return null;
});
}
}
testDataService(model) {
let profileType = "test";
let profileId = "test_profile";
let configCategory = "test";
return this.referenceDataService.getTestData(profileType, profileId, configCategory);
}

Angular2 HTTP Get Observable - How to wait for result

I am trying to validate a user token by the means of a back-end API. I am brand new to Angular2 in general. My question is, if I want isValidToken to return a boolean value of whether or not the token provided was valid, how can I wait for the HTTP call to complete prior to return in result from isValidToken()?
isValidToken(token: string): boolean {
var isValidToken: boolean = false;
this.getIsValidToken(token).subscribe(
data => {
isValidToken = data.isValidToken;
return isValidToken;
},
error => {
return false;
}
);
}
getIsValidToken(token: string) {
return this.http.get(this.validateTokenUrl + '?tokenString=' + token)
.map(res => res.json());
}
isValidToken needs to return Observable<boolean> or Promise<boolean>. It can't return the value synchronously because it relies on an asynchronous method for it's result.
It's turtles all the way down.
isValidToken(token: string): boolean {
return this.getIsValidToken(token);
}
getIsValidToken(token: string) {
return this.http.get(this.validateTokenUrl + '?tokenString=' + token)
.map(res => res.json());
}
then you can use it like
someMethod() {
this.isValidToken.subscribe(token => {
if(token) {
this.success = true;
// or some other code that should be executed when `token` is `true`
} else {
this.success = false;
// or some other code that should be executed when `token` is `false`
}
},
error => {
this.success = false;
// or some other code that should be executed when `token` is `false`
});
}
You can't go to sync execution from an async call. All you can do is return the observable (or promise) for the caller to be able to subscribe and register a callback to be called when data events are emitted or errors occur.

How to get the values of the subscribed data in angular2

I wrote a injectable service in which i want to return "display" in my data and i done it sucessfully as follows,
export class GetAllList {
str = localStorage.getItem('social');
loc = JSON.parse(this.str);
id = this.loc._id;
private _productUrl = 'http://localhost:3000/getprofiledetails/'+this.id;
constructor(private _http: Http) { }
getList(): Observable<IDetails[]> {
return this._http.get(this._productUrl)
.map((response: Response) => {
return response.json().data.display;
});
}
}
Here i am subscribing to it,
this._profileservice.getList()
.subscribe(
details1 => this.details1 = details1);
console.log("displaystas:"+this.details)
The problem is,my console is displaying undefined?so how can i see my display value in my console?Can anyone suggest me help.Thank you.
You are printing wrong variable (details instead of details1) and you are missing {}:
this._profileservice.getList()
.subscribe(
details1 => {
this.details1 = details1;
console.log("displaystas: " + this.details1)
}

Custom Route using Attribute Routing in WebApi

I'm working on retrieving list of Movie Details from DB using WebAPi. I've http verbs and it does work as normal. I've a scenario where i've to get records based on categories like Title, Date, Rating
WebConfig:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional, action = "ActionName" }
Controller :
[HttpGet]
[GET("api/GetMovieByCategory/{movieData}")]
public IEnumerable<MovieData> GetMovieByCategory(MovieData movieData)
{
IEnumerable<MovieData> movieDataByCat = null;
string[] paramCast;
if(movieData.Cast.Count()!=0)
paramCast = movieData.Cast;
IEnumerable<MovieData> GetAllMovies = null;
GetAllMovies = repo.GetAll();`
if (movieData.Cast == null || movieData.Cast.Count() == 0)
{
movieDataByCat = from data in GetAllMovies
where (data.Classification == (movieData.Classification == null ? string.Empty : movieData.Classification) ||
data.Genre == (movieData.Genre == null ? string.Empty : movieData.Genre) ||
data.Rating == movieData.Rating ||
data.ReleaseDate == movieData.ReleaseDate ||
data.Title == (movieData.Title == null ? string.Empty : movieData.Title))
select data;
}
return movieDataByCat;
}
Angular Service :
//GetByCategory
this.getbyCat = function (Movie) {
return $http.get("/api/values/GetMovieByCategory/" + Movie);
};
when i try to execute, i'm getting an exception as follows,
Remote Address:[::1]:50948
Request URL:http://localhost:50948/api/values/GetMovieByCategory/[object%20Object]
Request Method:GET
Status Code:404 Not Found
I've no idea how to overcome this and get it resolved. I'm in beginner level. Please help.
Rest of all verbs (get,put,post) are working fine.
Note : I've installed NugetPackage AttributeRouting.Web.Http; for Route.
Update 1 :
Contoller.js :
$scope.srchbycat = function () {
var Movie = {
_title:"",
_genre: "",
_classification:"",
_releaseDate: "",
_rating: "",
_cast: ""
};
Movie = {
_title: $scope.txttitle,
_genre: $scope.txtGenre,
_classification: $scope.txtClassification,
_releaseDate: $scope.txtDate,
_rating: $scope.user.txtRating,
_cast: $scope.txtCast
};
var promisePost = MyService.getbyCat(Movie);
Recent Error :
Remote Address:[::1]:50948
Request URL:http://localhost:50948/api/values/GetMovieByCategory/?_genre=sdf
Request Method:GET
Status Code:400 Bad Request
In the Angular Service, instead of appending the Movie object, pass it as parameter.
eg.
//GetByCategory
this.getbyCat = function (Movie) {
return $http.get("/api/values/GetMovieByCategory/", { params: Movie});
};
This will make the HTTP get with the the properties as url parameters.
And I dont think there is a need for the {movieData} parameter in the Route defined, since WebApi will automatically Serialize the url parameters to the object MovieData
eg.
index.js
angular.module('index.services', []).
factory('indexService', function ($http) {
var api = 'api/values/GetData';
var indexAPI = {};
indexAPI.getData = function (params) {
return $http.get(api, { params: params });
}
return indexAPI;
});
angular.module('index.controllers', ['index.services']).
controller('indexController', function ($scope, indexService) {
$scope.getData = function () {
var params = {
name: 'test',
age: '10'
};
$scope.errorOccured = false;
indexService.getData(params).then(function (response) {
$scope.data = response.data;
}, function (response) {
$scope.errorOccured = true;
});
}
});
angular.module('index', ['index.controllers']);
Index.cshtml
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.1/angular.js"></script>
<script src="~/Scripts/app/index.js"></script>
<div ng-app="index" ng-controller="indexController">
<button ng-click="getData()">Get Data</button>
<div ng-if="errorOccured==true">Error Occured</div>
<div ng-repeat="item in data">
<div>{{item}}</div>
</div>
</div>
DataRequestModel.cs
public class DataRequestModel
{
public string Name { get; set; }
public string Age { get; set; }
}
ValuesController.cs
public class ValuesController : ApiController
{
[HttpGet]
public IEnumerable<string> GetData([FromUri]DataRequestModel dataRequest)
{
return new string[] { dataRequest.Name, dataRequest.Age.ToString() };
}
}

Resources