How Ionic constructor works - constructor

I have a problem with ionic constructor. Actually a Java program constructor works line by line. But in my Ionic application I have called a back-end service and getting some data and populate my variables with the received data.
constructor(public navCtrl: NavController, public navParams: NavParams, public patientService: PatientServiceProvider, public scanner: BarcodeScanner) {
this.id = this.navParams.get('id');
this.patientService.searchPatientById(this.id).subscribe(res => {
this.id = res.id;
this.mobile = res.mobile;
this.fname = res.firstname;
this.lname = res.lastName;
console.log("print this:"+this.mobile);
});
this.mobile = this.navParams.get('mobile');
console.log(this.id);
console.log("****"+this.mobile);
}
In above code my service working fine. My problem is last line execute before the service call. That means my output will look like
5656
"****"+94758968989
print this:undefined
Why this happened. This is not executed line by line.

Your patientService returns an Observable, so so functionCall searchPatientById() is asyncron. That means that after the Functioncall the next lines will be executed and the part in the subscribe is executed when you get a result.
To avoid that, you have more options, for example you can create another method which should be executed AFTER the async call and than call that method at the end in the subscribe. Or you can use async/await like this:
constructor(public navCtrl: NavController, public navParams: NavParams, public
patientService: PatientServiceProvider, public scanner: BarcodeScanner) {
this.init();
}
async init() {
this.id = this.navParams.get('id');
let res = await this.patientService.searchPatientById(this.id);
this.id = res.id;
this.mobile = res.mobile;
this.fname = res.firstname;
this.lname = res.lastName;
console.log("print this:"+this.mobile);
this.mobile = this.navParams.get('mobile');
console.log(this.id);
console.log("****"+this.mobile);
}

Related

StateHasChanged not updating on Blazor server app

I am working on a Blazor Server app over a SignalR connection with an ASP.NET Core API, this code works fine in WebAssembly but for some reason it doesn't works in Blazor Server app.
I suspect the problem is that StateHasChanged() isn't making effect, since Console.WriteLine($"Company Name: {item.CompanyName}, Volumn: {item.Volume}"); is printing in console but MarketData isn't updating UI at StateHasChanged().
For more context; full code is explained here:
https://www.webnethelper.com/2022/01/aspnet-core-6-signalr-creating-real.html
But I guess it's just a common fix; but I can't find the solution.
I've also tried with InvokeAsync(() => StateHasChanged()); as mentioned here in stackoverflow but It didnt work. Can anyone help me fix this issue?
private HubConnection? hubConn;
private string? ConnectionStatusMessage;
public List<Market> MarketData = new List<Market>();
public List<Market> MarketReceivedData = new List<Market>();
private List<string> xSource;
private List<int> ySource;
private List<object> source;
protected override async Task OnInitializedAsync()
{
xSource = new List<string>();
ySource = new List<int>();
source = new List<object>();
await service.GetMarketEndpoint();
await Start();
}
private async Task Start()
{
hubConn = new HubConnectionBuilder().WithUrl("https://localhost:7193/marketdata").Build();
await hubConn.StartAsync();
if(hubConn.State == HubConnectionState.Connected )
ConnectionStatusMessage = "Connection is established Successfully...";
else
ConnectionStatusMessage = "Connection is not established...";
}
private void MarketDataListener(string chartType)
{
hubConn.On<List<Market>>("SendMarketStatusData", async (data) =>
{
MarketData = new List<Market>();
foreach (var item in data)
{
Console.WriteLine($"Company Name: {item.CompanyName}, Volumn: {item.Volume}");
xSource.Add(item.CompanyName);
ySource.Add(item.Volume);
}
source.Add(ySource);
source.Add(xSource);
MarketData = data;
StateHasChanged();
await js.InvokeAsync<object>(chartType, source.ToArray());
xSource.Clear();
ySource.Clear();
});
}
private void ReceivedMarketDataListener()
{
hubConn.On<List<Market>>("CommunicateMarketData", (data) =>
{
MarketReceivedData = data;
StateHasChanged();
});
}
public async Task Dispose()
{
await hubConn.DisposeAsync();
}
async Task generateLineChartTask()
{
MarketDataListener("marketLineChart");
ReceivedMarketDataListener();
await service.GetMarketDataAsync();
}
async Task generateBarChartTask()
{
MarketDataListener("marketBarChart");
ReceivedMarketDataListener();
await service.GetMarketDataAsync();
}
The main difference here is that Blazor Serverside is multithreaded so the callbacks from the circuit will execute on a different Thread.
StateHasChanged() has to be executed on the main (UI) thread so call it like InvokeAsync(StateHasChanged), which is short for InvokeAsync(() => StateHasChanged()).
And be aware of other threading risks. Ie, don't share data like Lists between threads.

How to get a specific value from a JSON object, like a name?

I use Angular as the front end of my application. For the backend I use glassfish. I currently use a Http GET verb to get a JSON object with an id and name and address. I only want to get the name of the object, how do I do that in a typescript file? How do I get the name of the newest added object of the rest server?
I want to get restaurantName from the object:
{ restaurantId: 1, restaurantName: 'Mcdonalds', restaurantAdres: 'Kalverstraat 5' },
Code that retrieves the object from the rest server:
ngOnInit() {
this.http.get('http://localhost:8080/aquadine-jee/resources/restaurant')
.subscribe(
val => {
const restStr = JSON.stringify(val);
console.log(restStr);
);
Backend code:
#GET
#Produces("application/json")
public Response all(){
List<Restaurant> all = repositoryService.getAllRestaurants();
return Response
.status(200)
.header("Access-Control-Allow-Origin", "*")
.entity(all)
.build();
}
public List<Restaurant> getAllRestaurants() {
EntityManager em = entityManagerFactory.createEntityManager();
List<Restaurant> restaurants = em.createQuery("SELECT r FROM Restaurant r").getResultList();
em.close();
return restaurants;
}
#Entity
#Table(name = "restaurant")
#NamedQueries({
#NamedQuery(name = "Restaurant.findOne", query = "select m from Restaurant m where m.id = :id"),
#NamedQuery(name = "Restaurant.getAll", query = "select m from Restaurant m")
})
public class Restaurant implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// #Column(name="naam")
// #NotBlank
// private String naam;
// #NotBlank
String restaurantName;
// #NotBlank
String restaurantAdres;
int restaurantId;
public Restaurant(){
}
public Restaurant(int restaurantId, String restaurantName, String restaurantAdres) {
this.restaurantId = restaurantId;
this.restaurantName = restaurantName;
this.restaurantAdres = restaurantAdres;
}
First, I'd create a class and maybe an interface to give you strongly typed objects in your TypeScript:
Then you can return the object from your get request as that object and use that however you want like result.restaurantName
A quick mock of what that looks like (using a stub method instead of http) is here:
In short though:
the class and interface for Angular:
export interface IRestaurant {
restaurantId: number;
restaurantName: string;
restaurantAddres: string;
}
export class Restaurant implements IRestaurant {
restaurantId:number;
restaurantName:string;
restaurantAddres:string;
}
And then the component that gets the data via a method, and uses essentially the JSON as an object:
export class AppComponent {
favoriteRestaurant: IRestaurant;
retrieve(){
this.favoriteRestaurant = this.getRestaurant();
alert(this.favoriteRestaurant.restaurantName);
}
getRestaurant():IRestaurant {
var result: Restaurant = {
restaurantId: 1,
restaurantName: 'Mcdonalds',
restaurantAddres: 'Kalverstraat 5'
};
return result;
}
}
Making it more useful for you though, change the http.get method to something like this:
ngOnInit() {
this.http.get('http://localhost:8080/aquadine-jee/resources/restaurant')
.subscribe(
val:IRestaurant => {
this.favoriteRestaurant = val;
console.log(restStr.restaurantName);
);
You don't want to use JSON.stringify above, because that gives you a string!
Additionally, your restaurantAddress is mispelled, these would need to match exactly. So I would correct the backend.

Passing JSON Object with NavController

I want to pass a JSON Object to another Page in Ionic 2.
I tried like the following, but I get the exception
Cannot read property 'user' of undefined.
Here
How to pass data in ionic2 someone asked the same, but it's without a clear, working answer.
var jsonData = JSON.parse(data);
this.navCtrl.push(InfoPage, {jsonData});
InfoPage
export class InfoPage {
jsonData = null;
user = null;
constructor(public navCtrl: NavController, private loadingCtrl: LoadingController, private navParams: NavParams) {
this.jsonData = this.navParams.get("jsonData");
}
ngOnInit()
{
this.user = this.jsonData.user;
console.log(this.user);
}
}
Not entirely sure, but i would think something like this would work. On the other hand, I would think that using an intermediary service for this will work much better.
On the page you want to send data from:
let jsonData = JSON.stringify(data);
this.navCtrl.push(InfoPage, {jsonData : jsonData});
On the page which retrieves the data:
export class InfoPage {
jsonData = null;
user = null;
constructor(private navParams: NavParams) {
this.jsonData = JSON.parse(this.navParams.get("jsonData"));
}
ngOnInit() {
this.user = this.jsonData.user;
console.log(this.user);
}
}
Let me again mention though, that it's better to store such data in a so called PageService which will be a singleton throughout your pages. You can use this to send data from one page to another. If you really want to stick with the parse/stringify, then I would expect my solution to work. Be aware that I didn't test it.
A second solution would be the use of a service, which perhaps you can use for other use-cases as well:
export class PageService {
public pageData: any;
}
You should add this service to your root providers array. After that you can use it inside your pages like this:
FirstPage (sender)
export class FirstPage {
private jsonData: any = {user: 'saskia'};
constructor(private pageService: PageService) {}
goToInfoPage(): void {
this.pageService.pageData = this.jsonData;
this.navCtrl.push(InfoPage);
}
}
InfoPage (receiver)
export class InfoPage {
user: string;
constructor(private pageService: PageService) {}
ionViewWillEnter() {
this.user = this.pageService.pageData.user;
console.log(this.user); //saskia
}
}
I'm using the ionViewWillEnter lifecycle hook, to assure that the data is obtained at the right time

WcfFacility and Sequence contains no elements error?

I have wcf library with service contracts and implementations.
[ServiceContract]
public interface IServiceProtoType
{
[OperationContract]
Response GetMessage(Request request);
[OperationContract]
String SayHello();
}
[DataContract]
public class Request
{
private string name;
[DataMember]
public string Name
{
get { return name; }
set { name = value; }
}
}
[DataContract]
public class Response
{
private string message;
[DataMember]
public string Message
{
get { return message; }
set { message = value; }
}
}
public class MyDemoService : IServiceProtoType
{
public Response GetMessage(Request request)
{
var response = new Response();
if (null == request)
{
response.Message = "Error!";
}
else
{
response.Message = "Hello, " + request.Name;
}
return response;
}
public string SayHello()
{
return "Hello, World!";
}
}
I have windows service project that references this library, where MyService is just an empty shell that inherits ServiceBase. This service is installed and running under local system.
static void Main()
{
ServiceBase.Run(CreateContainer().Resolve());
}
private static IWindsorContainer CreateContainer()
{
IWindsorContainer container = new WindsorContainer();
container.Install(FromAssembly.This());
return container;
}
public class ServiceInstaller : IWindsorInstaller
{
#region IWindsorInstaller Members
public void Install(IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
string myDir;
if (string.IsNullOrEmpty(AppDomain.CurrentDomain.RelativeSearchPath))
{
myDir = AppDomain.CurrentDomain.BaseDirectory;
}
else
{
myDir = AppDomain.CurrentDomain.RelativeSearchPath;
}
var wcfLibPath = Path.Combine(myDir , "WcfDemo.dll");
string baseUrl = "http://localhost:8731/DemoService/{0}";
AssemblyName myAssembly = AssemblyName.GetAssemblyName(wcfLibPath);
container
.Register(
AllTypes
.FromAssemblyNamed(myAssembly.Name)
.InSameNamespaceAs<WcfDemo.MyDemoService>()
.WithServiceDefaultInterfaces()
.Configure(c =>
c.Named(c.Implementation.Name)
.AsWcfService(
new DefaultServiceModel()
.AddEndpoints(WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format(baseUrl,
c.Implementation.Name)
)))), Component.For<ServiceBase>().ImplementedBy<MyService>());
}
#endregion
}
In Client Console app I have the following code and I am getting the following error:
{"Sequence contains no elements"}
static void Main(string[] args)
{
IWindsorContainer container = new WindsorContainer();
string baseUrl = "http://localhost:8731/DemoService/{0}";
container.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero);
container
.Register(
Types
.FromAssemblyContaining<IServiceProtoType>()
.InSameNamespaceAs<IServiceProtoType>()
.Configure(
c => c.Named(c.Implementation.Name)
.AsWcfClient(new DefaultClientModel
{
Endpoint = WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format(baseUrl,
c.Name.Substring(1)))
})));
var service1 = container.Resolve<IServiceProtoType>();
Console.WriteLine(service1.SayHello());
Console.ReadLine();
}
I have an idea what this may be but you can stop reading this now (and I apologize for wasting your time in advance) if the answer to the following is no:
Is one (or more) of Request, Response, or MyDemoService in the same namespace as IServiceProtoType?
I suspect that Windsor is getting confused about those, since you are doing...
Types
.FromAssemblyContaining<IServiceProtoType>()
.InSameNamespaceAs<IServiceProtoType>()
... and then configuring everything which that returns as a WCF client proxy. This means that it will be trying to create proxies for things that should not be and hence a Sequence Contains no Elements exception (not the most useful message IMHO but crushing on).
The simple fix would be just to put your IServiceProtoType into its own namespace (I often have a namespace like XXXX.Services for my service contracts).
If that is not acceptable to you then you need to work out another way to identify just the service contracts - take a look at the If method for example or just a good ol' Component.For perhaps.

Ehcache hangs in test

I am in the process of rewriting a bottle neck in the code of the project I am on, and in doing so I am creating a top level item that contains a self populating Ehcache. I am attempting to write a test to make sure that the basic call chain is established, but when the test executes it hands when retrieving the item from the cache.
Here are the Setup and the test, for reference mocking is being done with Mockito:
#Before
public void SetUp()
{
testCache = new Cache(getTestCacheConfiguration());
recordingFactory = new EntryCreationRecordingCache();
service = new Service<Request, Response>(testCache, recordingFactory);
}
#Test
public void retrievesResultsFromSuppliedCache()
{
ResultType resultType = mock(ResultType.class);
Response expectedResponse = mock(Response.class);
addToExpectedResults(resultType, expectedResponse);
Request request = mock(Request.class);
when(request.getResultType()).thenReturn(resultType);
assertThat(service.getResponse(request), sameInstance(expectedResponse));
assertTrue(recordingFactory.requestList.contains(request));
}
private void addToExpectedResults(ResultType resultType,
Response response) {
recordingFactory.responseMap.put(resultType, response);
}
private CacheConfiguration getTestCacheConfiguration() {
CacheConfiguration cacheConfiguration = new CacheConfiguration("TEST_CACHE", 10);
cacheConfiguration.setLoggingEnabled(false);
return cacheConfiguration;
}
private class EntryCreationRecordingCache extends ResponseFactory{
public final Map<ResultType, Response> responseMap = new ConcurrentHashMap<ResultType, Response>();
public final List<Request> requestList = new ArrayList<Request>();
#Override
protected Map<ResultType, Response> generateResponse(Request request) {
requestList.add(request);
return responseMap;
}
}
Here is the ServiceClass
public class Service<K extends Request, V extends Response> {
private Ehcache cache;
public Service(Ehcache cache, ResponseFactory factory) {
this.cache = new SelfPopulatingCache(cache, factory);
}
#SuppressWarnings("unchecked")
public V getResponse(K request)
{
ResultType resultType = request.getResultType();
Element cacheEntry = cache.get(request);
V response = null;
if(cacheEntry != null){
Map<ResultType, Response> resultTypeMap = (Map<ResultType, Response>) cacheEntry.getValue();
try{
response = (V) resultTypeMap.get(resultType);
}catch(NullPointerException e){
throw new RuntimeException("Result type not found for Result Type: " + resultType);
}catch(ClassCastException e){
throw new RuntimeException("Incorrect Response Type for Result Type: " + resultType);
}
}
return response;
}
}
And here is the ResponseFactory:
public abstract class ResponseFactory implements CacheEntryFactory{
#Override
public final Object createEntry(Object request) throws Exception {
return generateResponse((Request)request);
}
protected abstract Map<ResultType,Response> generateResponse(Request request);
}
After wrestling with it for a while, I discovered that the cache wasn't being initialized. Creating a CacheManager and adding the cache to it resolved the problem.
I also had a problem with EHCache hanging, although only in a hello-world example. Adding this to the end fixed it (the application ends normally).
CacheManager.getInstance().removeAllCaches();
https://stackoverflow.com/a/20731502/2736496