On my component init I'm getting data from the server
import {Rules} from "../../interfaces/interfaces";
rules: Rules
ngOnInit() {
this.tt = this.rulesService.getUserClientRules().subscribe(
t => {
console.log(t)
console.log(t.clientRules.canAll)
this.rules = t.clientRules
},
error => {
console.log(error.error.message)
}
)
}
My service code is
getUserClientRules(): Observable<Rules> {
return this.http.get<Rules>('/api/rules/getClientUserRules/')}
and I have interface like:
export interface Rules {
clientRules: any
}
I'm getting response like this:
{clientRules: {canAll: true, canSee: false}}
How I can push this object into my rules object? I want to use it like rules.canAll or rules.canSeeAll...
I need this strucrure rules { canAll: true, canSee: true } I need to use it for the checks like *ngIf="rules.canSee"
Thank you for your responses!!!
You can define props into Rules interface like this.
export interface Rules {
clientRules: { canAll: boolean, canSee: boolean, canSeeAll: boolean}
}
But if your response may have many variations I suggest you to use any type
Remove this.tt you dont need any. Simple do in subscription method. You dooing good.
Related
I want to pass an Laravel object to my Vue component. In Vue I want to parse the data to an JSON object and I already tried this solution.
In my blade I have this:
<creator :object="parseData({{ $object->toJson() }})"></creator>
And in my component I have this:
data() {
return {
object: null
}
},
methods: {
parseData(data) {
this.object= JSON.parse(data);
}
}
I also tried
props: ['object']
instead of data()
This gives me the following error:
[Vue warn]: Property or method "parseData" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
Can you tell me what I am doing wrong?
SOLVED
I tried it again today and for some reason it worked. Thanks for your time guys!
Your parseData method needs to be defined within the methods section of your JS.
Try:
data() {
return {
ball: null
}
},
methods: {
parseData(data) {
this.object= JSON.parse(data);
}
}
Edit: and do what #Piotr said :)
First: You didn't add property object to your component. To fix this you have to add this line
props: ['object'],
just before your data function.
Second: you have to define parseData function in methods part of your component. Fix it as follows:
methods: {
parseData () {
//your function logic
}
}
Vue needs to define methods, watchers, computed properties within proper section.
Now your code is compete.
So I am coming from a background of C# where I can do things in a dynamic and reflective way and I am trying to apply that to a TypeScript class I am working on writing.
Some background, I am converting an application to a web app and the backend developer doesn't want to change the backend at all to accommodate Json very well. So he is going to be sending me back Json that looks like so:
{
Columns: [
{
"ColumnName": "ClientPK",
"Label": "Client",
"DataType": "int",
"Length": 0,
"AllowNull": true,
"Format": "",
"IsReadOnly": true,
"IsDateOnly": null
}
],
Rows:[
0
]
}
I am looking to write an Angular class that extends Response that will have a special method called JsonMinimal which will understand this data and return an object for me.
import { Response } from "#angular/http";
export class ServerSource
{
SourceName: string;
MoreItems: boolean;
Error: string;
ExtendedProperties: ExtendedProperty[];
Columns: Column[];
}
export class ServerSourceResponse extends Response
{
JsonMinimal() : any
{
return null; //Something that will be a blank any type that when returned I can perform `object as FinalObject` syntax
}
}
I know StackOverflow isn't for asking for complete solutions to problems so I am only asking what is one example taking this example data and creating a dynamic response that TypeScript isn't going to yell at me for. I don't know what to do here, this developer has thousands of server-side methods and all of them return strings, in the form of a JSON or XML output. I am basically looking for a way to take his column data and combine it with the proper row data and then have a bigger object that holds a bunch of these combined object.
A usage case here after that data has been mapped to a basic object would be something like this.
Example:
var data = result.JsonMinimal() as LoginResponse; <-- Which will map to this object correctly if all the data is there in a base object.
var pk = data.ClientPK.Value;
I'm not exactly sure I understand, but you may want to try a simple approach first. Angular's http get method returns an observable that can automatically map the response to an object or an array of objects. It is also powerful enough to perform some custom mapping/transformation. You may want to look at that first.
Here is an example:
getProducts(): Observable<IProduct[]> {
return this._http.get(this._productUrl)
.map((response: Response) => <IProduct[]> response.json())
.do(data => console.log('All: ' + JSON.stringify(data)))
.catch(this.handleError);
}
Here I'm mapping a json response to an array of Product objects I've defined with an IProduct interface. Since this is just a "lambda" type function, I could add any amount of code here to transform data.
I'm working on an Angular 2 application, and I'm trying to use JSON data, either local/mocked or fetched via HTTP, and display it on a component. I have an injectable service that will do the fetching/mocking -
import { Injectable } from 'angular2/core';
#Injectable()
export class TestService {
testString:string = "";
testDetails: string = "";
constructor() { }
getTestDetails(): Promise<string> {
this.testDetails = {
"status": "success",
"message": "Data save successful",
"data": {
"Random_Data_1": "Random Data 1",
"Random_Data_2": "Random Data 2"
}
};
return Promise.resolve(JSON.stringify(this.propertyDetails));
}
}
And then I have a component that uses the service via Dependency Injection -
import { Component, OnInit } from 'angular2/core';
import {TestService} from "./test.service";
#Component({
selector: 'test',
templateUrl: './test.component.html',
styleUrls: []
})
export class TestComponent implements OnInit {
testDetails: string = "";
constructor(private testService: TestService) { }
ngOnInit() {
this.display();
}
display(): void {
this.testService.getTestDetails()
.then(
testDetails => {
this.testDetails = JSON.parse(testDetails);
},
errorMessage => {
console.error("Something failed trying to get test details");
console.error(errorMessage);
}
);
}
}
The component HTML -
<div class="content">
<p> Test Details </p>
<p> {{ testDetails.data.Random_Data_1 }} </p>
</div>
The problem is, the HTML is erroring out trying to display the items in the testDetails JSON. I initially used it with md-tabs, so the first try would error out, but the other tabs would read the data fine. Also, the ngOnInit would be called twice when the error occurs. I have narrowed it down to the data coming in and the object types that is causing me the headache.
I know I can create a Details class and declare testDetails of type Details, and then map the JSON data into the class, but the thing is, I want to work with generic data, and only know a few components that will be present in the data. Is there a way to read the JSON, and use the data without having to define a separate class for each scenario ?
I have a plunker with the most basic stuff set up. The actual setup runs fine on my local system up until where I try to access the JSON data in the HTML, at which point the browser throws a cryptic error. The skeleton code doesn't even run on Plunker. That said, the structure in the Plunker defines the structure of my app and the data flow. Plunker with the basic setup
What is the best way to achieve this ? What is the standard/best practice to do this ?
Throwing another option out there, since you asked about best way to achieve this. Might not be the best idea, this is subjective ;) But if I were you...
Thinking about the future, where you will use real backend, it could be nice to use mock json file. If/when you move over to a real backend, you wouldn't basically need to change anything else but the url of the requests :)
So I set up a simple example for you. Here I used Observables, but you can use Promises if you prefer that. Here's more info on HTTP if you want/need to read up on that. Most important thing is that you have the HttpModule imported in your app module.
You have your file with JSON and in your service make http-requests to that:
getTestDetails() {
return this.http.get('src/data.json')
.map(res => res.json())
}
Your display-method:
display() {
this.testService.getTestDetails()
.subscribe(data => {
this.testDetails = data;
});
}
And in the template use the safe navigation operator to safeguard null/undefined values:
<div class="content">
<p> Test Details </p>
<p> {{ testDetails?.data?.Random_Data_1 }} </p>
</div>
Here's a
Demo
As said, this is to give another approach on how to implement the things you want to achieve, and this would probably be my preferred way :)
Use
<p *ngIF="testDetails.data.Random_Data_1 "> {{ testDetails.data.Random_Data_1 }} </p>
This is because there is no data initially.Hope this helps you.
I have an issue with Observables in Angular 2
My component calls service function on Init like below:
delivery: IDeliveryCountry[];
ngOnInit() {
this.checkoutService._getInfo().subscribe(dev => this.delivery = dev);
}
This is how interface looks like IDeliveryCountry:
export interface IDeliveryCountry {
iso: string;
name: string;
}
This is how Service looks like:
_getInfo(): Observable<IDeliveryCountry[]> {
return this.http.get(this.deliveryCountryUrl)
.map((response: Response) => <IDeliveryCountry[]>response.json())
}
json file with data looks like this:
[
{
"iso":"se",
"name":"Sweden"
},
{
"iso":"dk",
"name":"Denmark"
}
]
My html file is just a simple ngFor loop:
<div *ngFor='let dev of delivery'>{{dev.iso}}</div>
So far all things works perfect, as expected I get back "se" and "dk" in UI.
The problem appears when I change a structure of data in my json file to following:
{
"country": {
"iso":"se",
"name":"Sweden"
}
}
I want data to only have one country with iso and name property for it. So my html file looks like following:
<div>{{delivery.iso}}</div>
But I am getting iso as undefined all the time
" Cannot read property 'iso' of undefined "
Thank you!
You should first of all use:
{{delivery.country.iso}}
The undefined error you are getting, is because the data is coming async, so use the safe navigation operator to avoid this:
{{delivery?.country?.iso}}
Demo
Optionally you could extract the data that is inside country, so you can shorten your code in your template from {{delivery?.country?.iso}} to just {{delivery?.iso}}, this can be done like so:
.map(res => res.json().country) // extract the data from the object country
You can just do this without ngFor since it is an Object
<div>{{delivery.country.iso}}</div>
After your comments, undefined is because the data is coming async, so use the elvis operator to avoid this:
{{delivery?.country?.iso}}
Alternatively you could change your service to return the DeliveryCountry[]
getInfo(): Observable<IDeliveryCountry[]> {
return this.http.get(this.deliveryCountryUrl)
.map((response: Response) => response.json())
.map(delivery => delivery.country);
}
Then:
ngOnInit() {
this.checkoutService.getInfo()
.subscribe(deliveryCountries => this.deliveryCountries = deliveryCountries);
}
Then:
<div *ngFor="let deliveryCountry of deliveryCountries">{{deliveryCountry?.iso}}</div>
I am trying to build an array of objects in VueJS and I am running into some issues with .$set and .$add.
For example, I need the following structure when adding new items/objects:
{
"attendees": {
"a32iaaidASDI": {
"name": "Jane Doe",
"userToken": "a32iaaidASDI",
"agencies": [
{
"name": "Foo Co"
}
]
}
}
}
New objects are added in response to an AJAX call that returns JSON formatted the same as above. Here is my Vue instance:
var vm = new Vue({
el: '#trainingContainer',
data: {
attending: false,
attendees: {}
},
methods: {
setParticipantAttending: function(data)
{
if (data.attending)
{
this.attendees.$add(data.userToken, data);
} else {
this.attendees.$delete(data.userToken);
}
}
}
});
This only works if I start with attendees: {} in my data but when I try attendees.length after adding an attendee, I receive undefined. If I use attendees: [], the new object does not appear to be added. And lastly, if I use .$set(data.userToken, data) it does not add in the 'token':{data..} format required.
What could be the issue here? What is the correct way to use $.add when starting with an empty array of objects?
UPDATE
I found that it works if I set attendees: {} and then, when adding a new object,
if (data.userToken in this.attendees) {
this.attendees.$set(data.userToken, data);
} else {
this.attendees.$add(data.userToken, data);
}
Not sure if there is a better way to accomplish this.
If you set attendees to an empty object ({}) it will not have a length attribute. That attribute is on Arrays.
If you set attendees to an empty array ([]) then you need to use $set (or really, I think you want .push()) – $add is intended for use on objects not on arrays.
I'm not quite following your last question – could you add more context?
EDIT 2:
The answer below was for Vue 1.x. For Vue 2.x and greater use:
this.$set(this.attendees, data.userToken, data);
More information here: https://v2.vuejs.org/v2/api/#Vue-set
EDIT:
Responding to your update, you should be able to just use $set in all cases. I.e. just do this:
this.attendees.$set(data.userToken, data);
As of version 0.6.0, this seems to be the correct way:
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
http://vuejs.org/guide/reactivity.html#Change_Detection_Caveats