I have read several articles on dependency injection and cannot seem to get it working the way I think it should. From what I have read, you can use the #Injectable decorator on a class and then the metadata is created for the DI like so:
import {Hero} from './hero.model';
import {Injectable} from 'angular2/angular2'
#Injectable()
export class HeroService {
constructor() {
console.log('Hero Service Created');
}
}
Then in your component, you can use it in your constructor (with the proper import) like this:
constructor(heroService: HeroService) {
console.log('App Component Created');
}
However, I get the following error: Cannot resolve all parameters for AppComponent(?). Make sure they all have valid type or annotations.
I am able to get it working properly if I remove the #Injectable syntax from the service and instead have my constructor like this:
constructor(#Inject(HeroService) heroService: HeroService) {
console.log('App Component Created');
}
With everything that I've read, these should do the same thing, but they aren't. Any ideas as to why? I am using Typescript 1.6.2 with VS 2013, angular 2 v2.0.0-alpha.46, and systemjs v0.19.5.
Make sure that you've specified "emitDecoratorMetadata" option in your TypeScript configuration.
Related
Happy Another Covid Day. When I use generate-all, Grails creates the Data Service for me. I begin to understand what a data service is.
I also have my own service for my Author and Book classes to use. I name my service ImportService. I have methods in the ImportService to clean up my book data read from a CSV file before the Data Service saves my books to the database. I also follow the instruction to make the Data Service an Abstract Class. So, I can put my own method in the Data Service.
Since the Author has its own AuthorService, and the Book has its own BookService, I want the different Data Service to access the method in my ImportService. So, I don't have to copy and paste the import CSV code multiple times. So, I put the line ImportService importService in the AuthorServie class and the BookService class. That does not go well. importService is always NULL inside the Data Service classes. I google the problem. They say I cannot inject another service to the grails.gorm.services.Service.
There is a post that says to make a bean. I am new to Grails. I have no idea what they are talking about even with the codes posted. Part of my background is Assembly Language, C, and Pascal. My head is filled with lingo like Top Down, Subroutine, library, Address, and Pointer. I have no idea what a Bean is.
This is what it is. I am wondering whether this is a bug or by design that you cannot inject a service to the gorm service.
Thanks for your "Pointer".
See the project at https://github.com/jeffbrown/tom6502servicedi. That project uses Grails 4.0.3 and GORM 7.0.7.
https://github.com/jeffbrown/tom6502servicedi/blob/main/grails-app/services/tom6502servicedi/ImportService.groovy
package tom6502servicedi
class ImportService {
int getSomeNumber() {
42
}
}
https://github.com/jeffbrown/tom6502servicedi/blob/917c51ee173e7bb6844ca7d40ced5afbb8d9063f/grails-app/services/tom6502servicedi/AuthorService.groovy
package tom6502servicedi
import grails.gorm.services.Service
import org.springframework.beans.factory.annotation.Autowired
#Service(Author)
abstract class AuthorService {
#Autowired
ImportService importService
// ...
int getSomeNumberFromImportService() {
importService.someNumber
}
}
https://github.com/jeffbrown/tom6502servicedi/blob/917c51ee173e7bb6844ca7d40ced5afbb8d9063f/grails-app/controllers/tom6502servicedi/AuthorController.groovy
package tom6502servicedi
import grails.validation.ValidationException
import static org.springframework.http.HttpStatus.*
class AuthorController {
AuthorService authorService
// ...
def someNumber() {
render "The Number Is ${authorService.someNumberFromImportService}"
}
}
Sending a request to that someNumber action will verify that the ImportService is injected into the AuthorService and the AuthorService is injected into the AuthorController.
$ curl http://localhost:8080/author/someNumber
The Number Is 42
I'm attempting to create a custom plugin block in Drupal. When attempting to actually access the services that I've registered I continue to get the following exception:
NOTICE: PHP message: Error: Class 'Drupal\MyNamespace\MyRegisteredService' not found in /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/Container.php on line 259 #0 /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/Container.php(173): Drupal\Component\DependencyInjection\Container->createService(Array, 'foo....')
I have registered the services correctly, and have set up dependency injection correctly (I believe) it's just accessing the services that is not working.
My file structure currently looks like:
- web
- modules
- custom
- foo
- foo.services.yml
- src
- MyService.php
- Plugin
- Block
- FooBlock.php
foo.services.yml looks like:
services:
foo.my_service:
class: Drupal\MyNamespace\MyRegisteredService
autowire: true
FooBlock.php looks like (simply for dependency injection):
namespace Drupal\foo\Plugin\Block;
use Drupal\MyNamespace\MyRegisteredService
use Drupal\Console\Bootstrap\Drupal;
use Drupal\Core\Block\BlockBase;
use GuzzleHttp\Client;
use Http\Client\Exception;
use phpDocumentor\Reflection\Types\Array_;
use stdClass;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class FooBlock extends BlockBase implements ContainerFactoryPluginInterface {
private $my_service;
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('foo.my_service'),
);
}
function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
Drupal\MyNamespace\MyRegisteredService $my_registered_service,
) {
$this->my_registered_service = $my_registered_service;
}
MyService.php looks like:
<?php
namespace Drupal\MyNamespace;
class MyService
{
static function say_hello()
{
return 'hello world';
}
}
I'm not sure if the way that I'm trying to set this up is incorrect or if I haven't set up dependency injection correctly. Some things that I have tried with no success is changing the namespace and removing Drupal\ from it but this changed little.
I've also tried following several guides (such as this) on how set up services, with little luck.
Any help would be appreciated.
I am not sure about the actual name of your service or namespace path, but I can see a few inconsistencies in your placeholder references:
Please change all references of Drupal\MyNamespace\MyRegisteredService to Drupal\foo\MyRegisteredService where foo is the name of your module. This should be lower cased.
Secondly Drupal\MyNamespace\MyRegisteredService references a class name MyRegisteredService whereas the example class name you give is MyService. These should be equal, so either go with one or the other.
I thought DI was implemented to allow use the same services over the application, and change them as needed. However this snippet (Angular 2.0.0-beta.0) refuses to work:
# boot.ts
import {ProjectService} from './project.service'
bootstrap(AppComponent, [ProjectService]);
# my.component.ts
export class MyComponent {
constructor(project: ProjectService) {
}
}
and with explicit service requirement it works:
# my.component.ts
import {ProjectService} from './project.service';
export class MyComponent {
constructor(project: ProjectService) {
}
}
The official doc is somewhat inconsistent, but has the same in the plunkr example:
# boot.ts
import {HeroesListComponent} from './heroes-list.component';
import {HeroesService} from './heroes.service';
bootstrap(HeroesListComponent, [HeroesService])
# heroes-list.component.ts
import {HeroesService} from './heroes.service';
Is this the intended way of DI usage? Why we have to import service in every class requiring it, and where are the benefits if we can't just describe the service once on boot?
This isn't really related to dependency injection. You can't use a class in TS that is not imported.
This line references a class and DI derives from the type what instance to inject.
constructor(project: ProjectService) {
If the type isn't specified by a concrete import, DI can't know which of all possible ProjectService classes should be used.
What you can do for example, is to request a type (ProjectService) and get a different implementation (subclass like MockProjectService or EnhancedProjectService,...)
bootstrap(HeroesListComponent, [provide(ProjectService useClass: MockProjectService)]);
this way DI would inject a MockProjectService for the following constructor
constructor(project: ProjectService) {
I'm following the tutorials display-data in angular.io.
I introduced a new class FriendsService to separate the controller logic and model concern. I Called FriendsService class in DisplayComponent class by using dependency injection, the dependency injection not working.
There's no errors in the console. The page doesn't display the component. This is the line causing the component not to display on the page.
constructor(friendsService: FriendsService)
The page loads and displays the components (display) if change the constructor to:
constructor()
I'm using angular2.alpha.34 , Typescript, ES6.
I solved it. Eclipse-Plugin was causing the issue. The plugin wasn't generating the ES5 complaint correct code.
I used "tsc --watch -m commonjs -t es5 --emitDecoratorMetadata app.ts" command described in angular.io website.
The eclipse-plugin generated code and the command "tsc" generated code is slightly different.
When using the "tsc" command I was achieving the expected behavior.
First you have to define the Service before that any component or directive.
If you have something like this
class Component {
constructor(svc: Service) {
}
}
class Service {
}
It will fail. In cases like this you should use fordwardRef or you just can declare it before your component.
class Service {
}
class Component {
constructor(svc: Service) {
}
}
Another thing is that you have to inject your service using viewBindings (see ComponentAnnotation documentation).
class Service {
}
#Component({
viewBindings: [Service]
})
class Component {
constructor(svc: Service) {
}
}
And you are good to go. I hope it helps.
I created a bare-bones datagrid using web-ui for testing and had it working just fine. Then I decided to try to declare it as a component. I changed around the library references and now it is giving me the above error when I try to run the application. You can see my file structure below. The reason I am getting the "ambiguous reference" message when I try to run it is that when I went into the auto-generated DataGrid.dart file in the out directory, it had the following declaration
import 'DataGrid.dart';
...
import '../DataGrid.dart';
I am confused as to why the generated code imports them both. One thing that I considered is that it could be because the DataGridPage.html file instantiates my DataGrid component and my DataGridPage.dart file imports DataGrid.dart so that it can have references to DataGridColumn (it needs to set the columns for the DataGrid). In DataGridPage.dart, I also attach to certain DataGrid events such as SortColumnChanged and SelectionChanged so I need to request a copy of my DataGrid instance in DataGridPage.dart (I don't think there is a way to attach to events from the web component instantiation in DataGridPage.html).
Any ideas about what I am doing wrong?
Here is my file structure:
DataGrid.dart
--------------------------------------------
library datagrid;
...
part 'DataGridColumn.dart';
part 'DataGridRow.dart';
class DataGrid extends WebComponent{...}
DataGridRow.dart
--------------------------------------------
part of datagrid;
class DataGridRow {...}
DataGridColumn.dart
--------------------------------------------
part of datagrid;
class DataGridColumn {...}
DataGrid.html
--------------------------------------------
[contains the component declaration UI]
DataGridPage.html
-----------------------------------------
...
<div is="s-datagrid" id="myDataGrid" ItemsSource="{{app.Assets}}" Columns="{{app.Columns}}"></div>
...
DataGridPage.dart
--------------------------------------------
import 'DataGrid.dart';
import 'Asset.dart';
void main() {
}
DataGridApp _app;
DataGridApp get app {
if (_app == null) {
_app = new DataGridApp();
}
return _app;
}
class DataGridApp{
//provides ItemsSource and DataGridColumn data
}
jmesserly has answered this on the github site. He said that you need to remove the component import in your main dart file. So in my example I would remove the import 'DataGrid.dart' statement from the DataGridPage.dart. The IDE will give you a warning but you can ignore it because it will actually be run from the out folder.
GitHub Web-UI Issue 342