So I have a very similar Application Structure to the example below
https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart
However, there is no root mutations defined there. I need to create one since I have to update the state that is dynamically created in vue-tables-2.
In my mutation-types.js I declared the name of the mutation as
export const UPDATE_CLIENTTABLE = 'UPDATE_CLIENTTABLE'
However, I'm not sure how to write the mutations in mutations.js There's no module defined because the state is dynamically created by vue-tables-2. I'm doing something like below but it doesn't work
[types.UPDATE_CLIENTTABLE] (state, data) {
state.ClientTableLine.data = data
}
You'll need to export your mutation in your mutations.js file
export const [types.UPDATE_CLIENTTABLE) = (state, data) => {
state.ClientTableLine.data = data
}
Then import it into your vuex set up
import * as mutations from './mutations'
export default new Vuex.Store({
mutations,
actions,
getters,
modules: {
cart,
products
},
strict: debug,
plugins: debug ? [createLogger()] : []
})
This is assuming your vuex set up is taken from the shopping car example
Related
In AngularJS i used$ rootScope to pass user data, for example:
$ rootScope.user = {
id: '4',
username: 'user'
...
};
$ rootScope.user.authenticated = false;
the data in $ rootScope was filled in every time a page was opened or updated using a query toSQL.
In Angular 9 i did not find the use of$ rootScope.
Tell me, where can such data be stored in Angular 9 and with what help can this functionality be implemented?
In angular, if you need anything like that, you create a service, provide it in root and inject it wherever you want it. For example:
The service:
// Create the service (providedIn: 'root') makes it available globally
#Injectable({providedIn: 'root'})
export class UserService {
user: any ={
id: '4',
username: 'user'
...
};
}
Using the service in a component:
#Component({...})
export class MyComponent implements OnInit {
_isAuthenticated: boolean;
// Inject the service
constructor(private _userService: UserService) {}
ngOnInit() {
// Using the service
this._isAuthenticated = _useService.user?.authenticated ?? false;
}
}
PS: The code above uses two interesting typescript features (which are new as I write this answer): optional chaining and Nullish Coalescing. You can always use a regular ternary operator instead of that:
this._isAuthenticated = _useService.user ? _useService.user?.authenticated : false
When my team and I migrated one of the projects from AngularJS to Angular, I took a look at when $rootScope was being used in the old app and it turns out it was used for identity/authentication 95% of the time. A few other use cases were regarding the spinner, browser related settings and edge cases.
It seems like your use case is similar to ours as well. I just folded that $rootScope.user into an existing AngularJS service called identity (or it could be auth, or whatever). So in each component that referred to that $rootScope.user, I replaced it with the following. The constructor is just dependency injection, allows you to use the variables within the identity service anywhere.
whatever.component.ts
currentUser = this.identity.currentUser
constructor(private identity: IdentityService) {}
The identity service looks something like the below. There's a getter function for the current user, and when it's not available, you look into the cookie, or otherwise, it's blank object (unauthenticated).
identity.service.ts
private _currentUser; //should only obtain currentUser via get currentuser()
constructor(private cookieService: CookieService) {}
get currentUser() {
if (!this._currentUser) {
this._currentUser = this.getUserFromCookie() || {}; //get from cookie
}
return this._currentUser;
}
getUserFromCookie() {
return this.cookieService.get('currentUser') ? JSON.parse(this.cookieService.get('currentUser')) : {};
}
Hopefully this gets you started and helps others as well.
Error:
Error: Template parse errors: Parser Error: Bindings cannot contain
assignments at....
line: <div>Closed: {{blah}}.find()...
HTML:
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="4px">
<div>Total: {{(issuesData$ | async)?.length}}</div>
<div>Closed: {{(issuesData$ | async)?.filter(data => {data.closedOn}).length}}</div>
</div>
I'm curious if it is possible to use find/filter without running into the template parse error when find/filter are called on a collection in the interpolation statement.
EDIT: Angular 2 - Bindings cannot contain assignments - This does not work for me because I'm passing in an Observable to the component. OnInit I assign the #Input data variable to the issuesData$ observable. Using something like {{getCount()}} in the interpolation results in no data. I tried implementing that like this:
ANGULAR:
#Input()
data;
ngOnInit() {
this.issuesData$ = this.data;
}
getCount(){
this.issuesData$.subscribe(data => {
return data.length;
})
}
HTML:
<div>Total: {{getCount()}}</div>
But there is nothing to subscribe to when the getCount() is called in the interpolation and this doesn't work either {{(getCount() | async}}
In this scenario you should use map and format the response in a way that makes the data easily consumable by the component/template.
Also you can't return a value from subscribe, you can assign a value though.
find returns one match, filter returns an array. You meant to use filter if you are wanting to see the total number of matches using length
If you use shareReplay the observable will be resolved once so it can be called multiple times using either async pipes or subscribe without incurring additional costs if it does something with external resources like making an http request.
Finally you should define types / definitions, typescript is (can be) strongly typed and this is a big advantage over javascript (what it supersedes).
Template.html
<div>Total: {{(issuesData$ | async)?.length}}</div>
<div>Closed: {{(issuesData$ | async)?.closedOnLength}}</div>
YourComponent.ts
import { Observable } from 'rxjs';
import { map, shareReplay } from 'rxjs/operators';
#Input()
data: Observable<{closedOn:any}[]>;
issuesData$: Observable<{length: number, closedOnLength: number}>;
ngOnInit() {
this.issuesData$ = this.data.pipe(map((_) => {
return {
length: _.length,
closedOnLength: _.filter(d => d.closedOn).length
};
}), shareReplay());
}
count: number;
readCount() {
// you can't return data in a subscribe callback, it is asynchronous
// you can assign a value though
this.issuesData$.subscribe(_ => this.count = _.length);
}
You should subscribe to your Observable and manually assign the variables you want in there instead, purely to reduce the complexity of your template code.
#Input()
data;
total: number;
closed: number;
ngOnInit() {
this.issuesData$ = this.data;
this.issuesData$.subscribe(next => {
this.total = next.length;
this.closed = next.filter(x => x.closedOn).length;
}
}
Then just use the total and closed variables in your template.
To call find or filter from the async array in the template, define the callback in the component class. For example, you can set the method isClosedOn as the filter callback:
<div>Closed: {{ (issuesData$ | async)?.filter(isClosedOn).length }}</div>
and define it as follows in the component class:
public isClosedOn = data => data.closedOn;
See this stackblitz for a demo.
Having an assets folder with :
/assets/images/image1.png
/assets/svg/svg1.svg
How to include it in an HTML template (not in a CSS file) in order to have angular/webpack to automatically enable cache-busting on it (transforming automaticallt assets/images/image1.jpg to assets/images/image1-4d5678xc0v987654v.jpg?
The goal is to handle cache and refresh it soon ASAP when an existing file gets updated.
With webpack, I used to do a :
<img src="<%=require("./assets/img/image1.jpg")%>" />
The only solution I found with angular is requiring all my images in the .ts file but it's quite a pain to do :
const image1src = require(`../assets/images/image1.jpg`);
class Component {
image1 = image1src; // contains image1-4d5678xc0v987654v.jpg
}
// and in template : <img [src]="image2" />
Is there something simplier ?
ps: I don't want to handle a query paremeter or custom name myself
pps: I don't want to inject these files through CSS (and I know it works when files are getting injected by css)
ppps: using a PWA is not an option in my case
Thanks
I created a pipe for this so I don't need to create variables inside a component as you did.
import {Pipe, PipeTransform} from '#angular/core';
#Pipe({
name: 'imgURL'
})
export class ImgURLPipe implements PipeTransform {
transform(value: string): string {
return require('../../../images/' + value); // specify here a correct src to your folder with images
}
}
To make the require works inside components or pipes, add this to your typings:
declare var require: {
<T>(path: string): T;
(paths: string[], callback: (...modules: any[]) => void): void;
ensure: (
paths: string[],
callback: (require: <T>(path: string) => T) => void
) => void;
};
Inside a template, it looks like this:
<img [src]="'myImage.png' | imgURL">
Remember to add a declaration of the pipe to your module.
are you using angular-cli?
Check this article, it explains how to manage the assets with angular-cli: https://kimsereyblog.blogspot.com/2017/09/manage-assets-and-static-files-with.html
Other solution would be to use css, eg:
background: url('../assets/fonts/roboto-v15-latin-regular.svg')
There is a set of components in my Angular 4 app in which each component
requires a certain set of properties from a different JSON file which it shows on its template.
I have created a common JSON file containing all the properties and I load it when the app-component is called using a service that holds those properties array.
I then inject that same service into different components and fetch the populated array. The values show in the HTML all fine.
However, this approach seems to be a bit time consuming especially when the constants grow in size. Loading thousands of constants all at once and injecting them into different components where few of them are required is not a good approach.
I was willing to work on an approach where I create specific contansts JSON file for each component and somehow load it when the component is actually initialized. This way I can save the burden of a heavy JSON object and only those properties would be loaded that are required by that component.
The load() method in my constants service looks something like this:
#Injectable()
export class ConstantsService {
constructor(private http: HttpClient) {
console.log('ConstantsService created');
}
constants = {};
load() {
var constants = {};
var cons = 'constants';
var constantsResourceUrl =
'path' + cons + '.json';
this.http.get(constantsResourceUrl)
.subscribe(result => {
this.constants = result;
},
error => this.log.error(constantsResource + ' could not be loaded')
);
}
}
And my Components look like this to get the value of the constants:
#Component({
selector: 'xyz',
templateUrl: './xyz.html',
styleUrl: './xyz.css'
})
export class MyComponent {
consts = {};
constructor(private constantsService: ConstantsService) {
consts = this.constantsService.constants;
}
}
Any help would be appreciated.
If did have similar dilema. To use db or json files for settings/parametars behavior. Dynamic content end up in db, and at the end I found that is little stupid to fetch and use http request to get static json content since that could be bundled in source. I did split it and use in multiple exported constant in ts. file like:
export const dummyLookupConst = `{
"queryNo": 0,
"id": 250,
...}
and then import it into components by need.
I think what I am asking for is not possible OOB, but I want to confirm.
We are in a process of upgrading to ES6 (using Babel). Project is a web-site, using AMD (requirejs). I would like to turn a utility module (foolib) into ES6, but consume it from either ES6 (using import) or existing ES5/AMD module.
// foolib.es6
export { // as expected, this doesn't work
method1: function () { ... },
value1: 123.456
};
// consumer1.es6
import foolib from "foolib";
// consumer2.js
define(["foolib"], function (foolib) {});
I understand that the solution is to change foolib.es6 as follows:
export function method1() { ... };
export let value1 = 123.456;
However in reality number of entries returned from foolib is ridiculous. So I was hoping there is a way to export existing object literal without rewriting every line.
Furthermore, I realize that this is most likely impossible, due to the differences between AMD import (using define) and import mechanism (later works with exports object that has values hanging off of it, including default value, while former expects a single value to be returned).
One possible solution that I think might work is to export my object as default from foolib.es6, and then tweak requirejs default loader to inspect imported value for being an esModule and return default value: value && value.__esModule && value.default || value. Should this work? (I'm still hoping there is an easier solution).
The syntax you are using to export the object is invalid because you are not giving the object a name, so it cannot be a named export, and you are not specifying that it is the default export, so it cannot be the default export. Change it to be the default export:
// foolib.es6
export default {
method1: function () {},
value1: 123.456
}
// consumer.es6
import foolib from "foolib";
console.log(foolib.value) //=> 123.456
You can use the babel-plugin-add-module-exports Babel plugin to reinstate a default export as the value of module.exports in Node-land.
And as you discovered, make sure you include this plugin before any other -modules- plugins, for example transform-es2015-modules-amd.
This might be late but alternatively you can use the named export as well which is a little different from the default approach that #sdgluck mentioned.
const method1 = function () {};
const value1 = 123.456;
export { method1, value1 };
I like this approach because you can import them directly like
import { method1, value1 } from 'foolib';
without reaching out to the default variable.