I have the /coaching route.
If I am a super-admin, I can see the list of all coach-admins from the system (guess right, when going on /coaching route (pressing a button)).
If I am a coach admin, I can see the list of all coaches from the system. (Again, I want to use the same /coaching route).
I have created 3 components in this case: CoachAdminListComponent, CoachListComponent and CoachComponent. The html of the CoachComponent looks like the following:
<app-coach-admin-list
*ngIf="isCurrentUserSuperAdmin()"
[items]="coachAdmins$ | async"
[itemInfo]="coachAdminInfo$ | async"
[loggedUser]="loggedUser"
[cachedItems]="allCoachAdmins$ | async"
[loading]="loading"
(onSubmit)="handleOnSubmit($event)"
(onFilter)="handleOnFilter($event)"
(onMenuItem)="handleOnMenuItem($event)">
</app-coach-admin-list>
<app-coach-list
*ngIf="!isCurrentUserSuperAdmin()"
[items]="coaches$ | async"
[itemInfo]="organisationInfo$ | async"
[loggedUser]="loggedUser"
[cachedItems]="allCoaches$ | async"
[loading]="loading"
(onSubmit)="handleOnSubmit($event)"
(onFilter)="handleOnFilter($event)"
(onMenuItem)="handleOnMenuItem($event)">
</app-coach-list>
I understand that this is an ugly code, but how can I display each component when the role is convenient for them?
I got the following error when trying to log in as a coach admin:
ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression
has changed after it was checked. Previous value: '[object Object]'.
Current value: 'false'.
The coach.module.ts:
const routes: Routes = [{
path: 'coaching',
component: CoachComponent,
canActivate: [AuthGuard]
}];
Of couse, the coach component has the 2 modules included in its file, so I am trying to find how to render this without having the error and also in a clear manner?
Thanks.
Try Setting up isCurrentUserSuperAdmin as a property and not a function,
set it in the ngOnInit().
Your Component Class now look like
export class CoachComponent implements OnInit{
isUserSuperAdmin:boolean;
public ngOnInit(){
this.isUserSuperAdmin = this.CheckIfSuperAdmin();
}
public CheckIfSuperAdmin(){
//your logic to check if super admin
}
}
Related
FYI: Products is my cms element name.
As shown in shopware 6 guides, I have created a file
DataResolver/ProductsCmsElementResolver.php
which has an enrich method which helps to extend data. In there I try to access the configs of my custom cms element with:
$config = $slot->getFieldConfig();
$productListType = $config->get('products')->getValue();
That, however always returns the default value that was set during the registration of the element:
Shopware.Service('cmsService').registerCmsElement({
name: 'products',
label: 'das.elements.customProductsElement.label',
component: 'sw-cms-el-products',
configComponent: 'sw-cms-el-config-products',
previewComponent: 'sw-cms-el-preview-products',
defaultConfig: {
products: {
source: 'static',
value: ''
}
}
});
I did it exactly as it is shown in the following guides:
https://developer.shopware.com/docs/guides/plugins/plugins/content/cms/add-cms-element
https://developer.shopware.com/docs/guides/plugins/plugins/content/cms/add-data-to-cms-elements#create-a-data-resolver
Could anyone share a sample of code where you get the value of config as a variable and not static value?
What I was doing wrong was that I forgot to write the .value in computed methods:
computed: {
products() {
return this.element.config.products.value;
}
},
However I also found such function call in shopware source codes which was not mentioned in the docs:
methods: {
createdComponent() {
this.initElementConfig('youtube-video');
this.initElementData('youtube-video'); // this line was not present in docs
}
}
I assume you haven't done any further handling of the product data in your config component, as you do not mention it.
I suggest having a look at the default cms components like for example shopware/administration/Resources/app/administration/src/module/sw-cms/elements/product-slider/config/index.js where you can see how product data is handled :)
As Angular, NgRx-Data and NestJs are becomming more and more popular, I feel there may be quite a few programmers who are wondering about the querying syntax for the following.
I have a running prototype of a client (front end) composed in Angular 8 with NgRx-Data.
On the back end is a NestJs based server + MySQL.
I can nicely retrieve and pass data between all parts, except queries. I do not seem to be able to find proper documentation on the syntax.
Here is the example of how the client is set:
// Simple entity example (all ngrx-data metadata are declared and set):
export class Hero {
id: number;
name?: string;
age?: number;
}
Entity Service / for fetching data
#Injectable({providedIn: 'root'})
export class HeroService extends EntityCollectionServiceBase<Hero> {
constructor(serviceElementsFactory: EntityCollectionServiceElementsFactory) {
super('Hero', serviceElementsFactory);
}
}
Component for showing data
#Component({
selector: 'hero-comp',
templateUrl: './hero.component.html',
styleUrls: ['./hero.component.scss']
})
export class HeroComponent {
heroData$: Observable<Hero[]>;
constructor(private heroDatService: HeroService) {
this.heroData$ = this.heroDatService.entities$;
}
private getAllData() {
// This works nicely, I get all records from the db via server
this.heroDatService.getAll();
}
private queryData() {
// This queryParams syntax fails - server complains with this error:
// [HttpExceptionFilter] GET /hero/?age>20
// QueryFailedError: ER_EMPTY_QUERY: Query was empty
// QUESTION: What is the proper syntax?
let queryParams: QueryParams = {
'age > 20'
}
this.fetchDataService.getWithQuery(queryParams);
}
Here is the server related code excerpt: -
(there is a service, but for simplicity here, I moved the repo functions to the controller functions):
#Controller('hero')
export class HeroController <Hero> {
constructor(readonly repo: Repository<Hero>) {}
// This returns nicely all Hero records from the MySQL db server
#Get()
async getAll(): Promise<Hero[]> {
return await this.repo.find();
}
// This does not work !
// I am not sure about any piece of the code here !
#Get('query')
async query(#Query() sql): Promise<any> {
// Does the sql argument need to be manipulated into parameters: {...} ?
// If yes - how ?
let parameters: undefined;
return await this.repo.query(sql, parameters);
}
Please see the comments above each code line - the problems are spelled out there.
And here are the important questions:
On the client how do we properly pass query criteria for some of these examples:
- {'age > 20'}
- {'age BETWEEN 20 AND 40'}
- {'age = 20 OR age = 30 OR age = 40'}
- {'name = "Superman"'}
- {'name LIKE "Super%"'}
- etc.
Also, what would be the syntax for passing a full SQL sentence, such as:
- {'SELECT * FROM Heroes WHERE name LIKE "Super%" AND Age > 20;'}
and getting the result from the server.
What needs to be done on both ends (client and server) for these queries to work?
All inputs much appreciated.
It seems like you're confused about HTTP Query parameters and SQL querying, which are two different topics. Query parameters, in the context of HTTP, are parameters that can be passed from the client to the server and modify the outcome of the HTTP call. Query parameters are always passed starting with a ? in the URL in the form of <key>=<value> and separated with an &.
A SQL Query is a specific string that tells a SQL server what table to query against, for what columns, with what conditions. Usually in the form of SELECT <columns> FROM <table> WHERE <conditions>;, but they can be much more complex than that.
Now that definitions are out of the way, the endpoint you are trying to reach should be /hero/query. You'll need to end up doing a lot of data processing on the server side of things, sanitization, ensuring that the incoming string is proper for SQL WHERE clauses, ensuring that you won't be vulnerable to SQL Injections (if you pass the query params straight to your query, you will be), but a very very naive approach would look something like this:
#Controller('hero')
export class HeroController {
constructor(#InjectRepository(Hero) private readonly repo: Repository<Hero>) {}
#Get('query')
queryForHero(#Query() queryParam) {
return this.repo.query(`SELECT <field_go_here> FROM Hero WHERE ${queryParams.query};`);
}
}
For the love of all that is good in the world, do not actually use the above code. It is 100% vulnerable to all kinds of SQL injections.
A corresponding request could look something like
curl http://<host>/hero/query?query=Name%3D%27Superman%27
This would cause the server to use the query
SELECT <fields_go_here> FROM Hero WHERE Name='Superman';
You'll really want to add in a ton of validations on what is coming into your server before just sending it to your SQL server lest you end up like Little Bobby Table.
Hopefully this helps get you on the right path.
I am beginner in sylius work and i would like to create adjustement on order item before it will be persist in database. So i create a listener base on sylius.order_item.pre_create event as it is said in the documentation https://docs.sylius.com/en/1.5/book/architecture/events.html
All Sylius bundles are using SyliusResourceBundle, which has some built-in events on this format for exemple
sylius.resource.pre_create
Her is my Listener Config
services:
app.listener.order_item:
class: App\EventListener\OrderItemListener
tags:
- { name: kernel.event_listener, event: sylius.order_item.pre_create, method: onSyliusOrderItemPreCreate }
Her is my Listener Class
<?php
namespace App\EventListener;
use Symfony\Component\EventDispatcher\GenericEvent;
use Sylius\Component\Core\Model\ShopUserInterface;
use App\Entity\Order\OrderItem;
use App\Entity\Order\Order;
use App\Entity\Order\Adjustement;
use App\Repository\Channel\ChannelPricingRepository;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Order\Factory\AdjustmentFactoryInterface;
class OrderItemListener
{
public function onSyliusOrderItemPreCreate(GenericEvent $event)
{
var_dump(''); die;
$orderItem = $event->getSubject();
Assert::isInstanceOf($orderItem, OrderItem::class);
}
}
But nothing happens when i add a new product to card. What i miss? May be i don't understand well concept or i make thing in wrong way. Please help me.
I have found solution for my problem. In fact when adding product to card route sylius_shop_ajax_cart_add_item is called with post method. Doing bin/console debug:router sylius_shop_ajax_cart_add_item show that Sylius\Bundle\OrderBundle\Controller\OrderItemController::addAction method is excecuted. In this one $this->eventDispatcher->dispatchPreEvent(CartActions::ADD, $configuration, $orderItem); is called and CartActions::ADD = 'add'.
So the event her is sylius.order_item.pre_add not sylius.order_item.pre_create as i made it.
services:
app.listener.order_item:
class: App\EventListener\OrderItemListener
tags:
- { name: kernel.event_listener, event: sylius.order_item.pre_add, method: onSyliusOrderItemPreAdd }
thanks.
I'm trying to make pagination in Vuejs 2 project
i write a code like in this demo
https://jsfiddle.net/os7hp1cy/48/
it's work fine in Vuejs 1 (vue-1.0.23)
however when i use this code with Vuejs 2 (vue#2.4.2) it's show me this error message :
[Vue warn]: Property or method "paginate" is not defined on the instance
but referenced during render. Make sure to declare reactive data
properties in the data option.
(found in <Root>)
how i can fix that error
thanks
In your code have this line:
v-for="user in users | filterBy searchKey | paginate"
And all filters are removed in vue2 so your code won't work https://v2.vuejs.org/v2/guide/migration.html#Filters
Moreover, you should not mount vue to body:
[Vue warn]: Do not mount Vue to <html> or <body> - mount to normal elements instead.
You can check my working code: https://jsfiddle.net/os7hp1cy/187/
I've forked #imcvampire's code and make a working version for Vue 2 due to this filter migration https://v2.vuejs.org/v2/guide/migration.html#Filters-Outside-Text-Interpolations-removed.
paginate method is moved to computed:
paginate: function() {
if (!this.users || this.users.length != this.users.length) {
return
}
this.resultCount = this.users.length
if (this.currentPage >= this.totalPages) {
this.currentPage = this.totalPages
}
var index = this.currentPage * this.itemsPerPage - this.itemsPerPage
return this.users.slice(index, index + this.itemsPerPage)
}
WARNING: I didn't apply the text filter, just the pagination first.
https://jsfiddle.net/c1ghkw2p/
I'm trying to create a small EmberJS application, but I'm struggling about how to architecture it correctly. I have a main view called "library" which displays on a sidebar a list of folders. User can click on each folder and display the content at the center (while the sidebar is still active).
I therefore have a library resource, and nested resources to display the folders in this specific context:
this.resource('library', function() {
this.resource('libraryFolders', {path: 'folders'}, function() {
this.resource('libraryFolder', {path: ':folder_id'};
}
};
To be able to access the folders in the parent root, I set up a dependency:
App.LibraryController = Ember.Controller.extend({
needs: ["libraryFolders"],
folders: null,
foldersBinding: "controllers.libraryFolders"
});
App.LibraryRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('controllers.libraryFolders.model', App.Folder.find());
}
});
First question: is this a good way? I feel it a bit strange that a parent controller have a dependency to its children.
Now, another problem arises: what if I want to reuse folders in another context? All the methods I would write in LibraryFoldersController would be specific to this one, not really DRY. What I came up is adding a root "folders" resource, and add the dependency to this one instead:
this.resources('folders');
App.LibraryController = Ember.Controller.extend({
needs: ["Folders"],
folders: null,
foldersBinding: "controllers.folders"
});
App.LibraryRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('controllers.folders.model', App.Folder.find());
}
});
What do you think? Am I doing it wrong?
IMO it looks good so far. You are using the needs API which is the correct (ember) way to setup dependencies between controllers.
Maybe if you find yourself writing repeating code you could consider creating a Mixin for a more general controller an put there your logic, that should be agnostic to the use cases it handles.
For example defined a mixin:
App.ControllerMixin = Ember.Mixin.create({
// "use case" agnostic logic here
});
You mix mixins into classes by passing them as the first arguments to .extend.
App.LibraryController = Ember.ObjectController.extend(App.ControllerMixin, {
// now you can use here the logic defined in your mixin
// and add custom code as you please
});
Another possibility is to write a super class and then extend from it to inherit common logic:
Snippet taken from the docs:
App.Person = Ember.Object.extend({
helloWorld: function() {
alert("Hi, my name is " + this.get('name'));
}
});
var tom = App.Person.create({
name: 'Tom Dale'
});
tom.helloWorld(); // alerts "Hi, my name is Tom Dale".
One thing worth mentioning (though I think it's simply a typo) is: needs: ["Folders"] should be needs: ["folders"],
Hope it helps.