leftstick / generator-es6-angular

Yeoman generator for es6 based angular skeleton
https://leftstick.github.io/generator-es6-angular
MIT License
74 stars 18 forks source link

How to about this framework #15

Closed chenhao21 closed 7 years ago

chenhao21 commented 7 years ago

Thanks for this great framework. With simply copy paste, we can add features, routes, components. I have put all compoents under common/componets/subs, and home/components/subs, add routes to home/routes, and works well.

I have some questions, because I am a learner of Angular: How to use html template for components. How to use Jquery in controllers, How to output $ctrl.variables into html document. I have tried like

{{variables}}

and

{{$ctrl.variables}}

, but not working.

Thank you very much.

leftstick commented 7 years ago

OK, it seems you are not familiar with angularJS and AngularJS styleguide (ES2015). It would be good if you read them first.

I am going to answer your questions in following section, and all my tutorials shall be based on the home feature.

And be aware that, i just put the different part in following snippets, which means you would not get it up and running without the original codes

How to use $http service

Pick up the /js/features/home/service/HomeService.js, and inject $http service:

export default class {

    /*@ngInject*/
    constructor($q, $http) {
        this.$q = $q;
        this.$http = $http;
    }

   //getInitTodos gets removed here, cause it has nothing to do with $http toturial

    getGithubUser() {
        return this.$http.get('https://api.github.com/users/leftstick');
    }
}

Use it in /js/features/home/components/home.co:

export default {
    template: `
        <logo></logo>
        <description></description>
        <github></github>
        <todo-app list="$ctrl.todos" loading="$ctrl.loading" on-toggle="$ctrl.toggleTodo(todo)" on-add="$ctrl.addTodo(todo)" on-archive="$ctrl.archive()"></todo-app>
        <footer></footer>
    `,
    controller: class {
        /*@ngInject*/
        constructor(HomeService) {
            this.HomeService = HomeService;
            //todos, loading get removed
        }

        $onInit() {
            //call of this.HomeService.getInitTodos() gets removed

            this.HomeService
                .getGithubUser()
                .then((info) => {
                    console.log('user ', info);//info shall be printed here
                });
        }

       //addTodo, toggleTodo, archive, $onDestroy get removed here

    }
};

If you are going to execute my snippet locally at your laptop, be sure turn off $httpProvider.defaults.withCredentials = false; in /js/fw/config/SSOConfig.js due to CORS credential issue

How to html template for component

That super easy, let's update js/features/home/components/home.co a bit:

import './home.css';
import tpl from './home.html';
export default {
    template: tpl,
    controller: class {
        /*@ngInject*/
        constructor(HomeService) {
            this.HomeService = HomeService;
        }

        $onInit() {
            this.HomeService
                .getGithubUser()
                .then((info) => {
                    console.log('user ', info);
                });
        }
    }
};

And create /js/features/home/components/home.html right next to home.co, with template content:

<logo></logo>
<description></description>
<github></github>
<todo-app list="$ctrl.todos" loading="$ctrl.loading" on-toggle="$ctrl.toggleTodo(todo)" on-add="$ctrl.addTodo(todo)" on-archive="$ctrl.archive()"></todo-app>
<footer></footer>

How to use jquery in controller

Technically, you shouldn't use jquery in controller. You are lacking of basis of MVC structure.

I believe your question is what you should do if you really need manipulating DOM, right?

That's why i put a directive at js/features/common/directives/autofocus.js, and you would see it is used at js/features/home/components/subs/todo/index.co:

<input autofocus type="text" placeholder="Typing here..." ng-keyup="$ctrl.addTodo($event)">

How to use variable in template

{{$ctrl.variables}} should work, and the example is everywhere in this scaffold, like $ctrl.todos, $ctrl.loading.

If you cannot get it in template, it means you might miss define it or define it in wrong place

chenhao21 commented 7 years ago

Thank you very much! Where can I see the console log info, from the console run npm.start , there is no output. I just insert the getGithubUser function as you did.

I have output variable in home.co like this: {{greeting.text}} controller: class { /@ngInject/ constructor(HomeService, $scope) { $scope.greeting = {text: 'Hello'}; } } But in todos/index.co, you are using $ctrl.variables like: $ctrl.loading what's the diffrence to use $ctrl or $scope.

And , I was confused by this code, how to handle it? bindings: { loading: '<', list: '<', onAdd: '&', onToggle: '&', onArchive: '&' },

leftstick commented 7 years ago

there is no output that's weird, cause i am pretty sure it's valid code. Maybe you got some errors?

If you are using $scope.greeting = {text: 'Hello'}; for variable definition, then just {{ greeting.text }} should working.

If you are asking difference between $ctrl and $scope, even bindings issue, you should check out: component-doc for more detail about component.

chenhao21 commented 7 years ago

Yes, I can see console.log output from firefox console's logging tab, it shows: Error: this.$http is undefined.

leftstick commented 7 years ago

Have you done like i did in /js/features/home/service/HomeService.js as following:

/*@ngInject*/
constructor($q, $http) {
        this.$q = $q;
        this.$http = $http;
}

Without giving it to this.$http, it shall be undefined by default

chenhao21 commented 7 years ago

Thank you!It solved. I have another question about template, can I change template dynamically, because I want to put all components in home feature, don't want to make a lot of features, and change the home.co's template when route changes.

leftstick commented 7 years ago

OK, so you want just one feature, but with routes involved, right? I think it goes away from my original ideal. And requires significant change to the scaffold

chenhao21 commented 7 years ago

Because every feature include the same logo, menu, footer, although I have put these compnents into common feature, but in every route's template, I have to include the same set of componets(logo,menu,footer). Is there a way to switch only the content component, and define the logo, menu, footer only in one template file?

If I can use "ui-view" to switch the content when routes changes, so I only need one home feature with diffrent routes. Is it possilble?

chenhao21 commented 7 years ago

Can I use bootstrap with this framework? How to import bootstrap?

leftstick commented 7 years ago

Of course you can use bootstrap,

First of all, install it with npm install --save bootstrap;

Then just open js/fw/ext/main.js, import css:

import 'angular-route';
import 'bootstrap/dist/css/bootstrap.css';
//if you need js, import it as well. But don't forget use directive as wrapper of js functions. calling bootstrap.js functions from controller is absolutely not a good idea
import 'bootstrap/dist/js/bootstrap';

export default ['ngRoute'];
chenhao21 commented 7 years ago

Hi, I want to use $urlRouterProvider and $stateProvider, which can support ui-view, may you modify routeConfig.js to support $stateProvider?

leftstick commented 7 years ago

Since ui-router is more powerful & complicated, i can not give you a simple way to do that, cause too many scenarios need to be concerned. You have to find your own way.

chenhao21 commented 7 years ago

I have inject $stateProvider into routerConfig.js and add below code into config(), but it not work.

ext/main.js
import 'angular-route';
import uiRouter from 'angular-ui-router';
export default ['ngRoute',uiRouter];

routerConfig.js
routes.forEach(function(ro) {
$stateProvider
.state(ro.id, {
url: ro.when,
template: ro.template
});
});

nothing displayed in the home page. Can you help me out of this, I have no idea.

leftstick commented 7 years ago

I haven't tried ui-router before. Not sure if your usage is correct. You need to check if error occurs, then read more usage from ui-router website

chenhao21 commented 7 years ago

When I import jquery, the console tells below error: import 'angular-route'; import $ from 'jquery';

export default ['ngRoute',$];

Error: [$injector:modulerr] Failed to instantiate module demo due to: [$injector:modulerr] Failed to instantiate module function ( selector, context ) due to: [$injector:unpr] Unknown provider: selector http://errors.angularjs.org/1.6.2/$injector/unpr?p0=selector minErr/<@http://127.0.0.1:8080/0.bundle.js:2429:12 createInjector/providerCache.$injector<@http://127.0.0.1:8080/0.bundle.js:7011:19 getService@http://127.0.0.1:8080/0.bundle.js:7164:1 injectionArgs@http://127.0.0.1:8080/0.bundle.js:7189:1 invoke@http://127.0.0.1:8080/0.bundle.js:7215:18 loadModules/<@http://127.0.0.1:8080/0.bundle.js:7122:28 forEach@http://127.0.0.1:8080/0.bundle.js:2718:11 loadModules@http://127.0.0.1:8080/0.bundle.js:7101:5

leftstick commented 7 years ago

jquery is not an angular module, why you want to export it as an angular module?

remove it from export, just:

import 'angular-route';
import 'jquery';

export default ['ngRoute'];
chenhao21 commented 7 years ago

Thank you!

I want to use $ in html, but console says: Error: $ is not defined

leftstick commented 7 years ago

$ is not a global variable, and it should not be.

So you have to import $ from 'jquery' first where you need it.

This is about modularization, you should learn about it before start coding

chenhao21 commented 7 years ago

where shall I put the import code? Like: import $ from 'jquery'. I am migrating exsiting jquery html source into your framework. So they use below code in the head of the html.

When I made a component, I will put my html template in a html file which with be imported into *.co file. So in which file shall I import and how to import?

leftstick commented 7 years ago

If you have jquery imported with script tag in your html(not component template). No need import it any more, just use $, it is global variable.

chenhao21 commented 7 years ago

in the common feature , I have made controller directory, and define controller like this: export default { type: 'controller', name: 'ControlerBase',

controllerFactory: function ($scope,$rootScope) {
}

} and I exported it from common feature. and I write declareControls() and call it from main.js export function declareControls(app, controls) { controls .filter(dir => { const shouldUse = isInjectedFunction(dir.controllerFactory) && dir.name; if (!shouldUse) { console.warn('controller defined without property [name], or method [controllerFactory]'); } return shouldUse; }) .forEach(dir => { //console.log(dir.name, dir.controllerFactory); return app.controller(dir.name, dir.controllerFactory); }); }

Then when I want to use my controller in home.co, like this: controller: myController

It says myController is undefined.

Please help me!