Xiaopei's DokuWiki

These are the good times in your life,
so put on a smile and it'll be alright

User Tools

Site Tools


it:ionic

ionic

  1. ionic 的 核心 是针对 hybrid app 的 前端 view 框架, 用来对不同的 mobile 平台提供 best practice 的设计, 类似 bootstrap 之于浏览器
  2. 同时 ionic 包含了 angularjs, 来实现前端的 model 和 controller 级别的功能.
  3. 另外 ionic 有一套命令行工具,
    1. 工具既包括 ionic 的 scaffolding 功能
    2. 又集成了 cordova (cordova 需要额外安装), 以实现 android 和 ios 的应用打包
  4. 但是 android 和 ios 的打包的环境都需要额外安装 (android 命令行工具(android sdk tool), android sdk(4.4), xcode, etc)

非 ionic 的 angular

使用 ios/android 的虚拟机

$ cd myApp
$ ionic platform add ios
$ ionic build ios
$ ionic emulate ios

Customizing Ionic With Sass (Build, gulp)

# 开启  sass 支持
$ ionic setup sass
$ ionic serve

使用 fontello

$ cp /tmp/fontello-xxx app/www/lib/fontello
 
app/www/lib/fontello/css $ ln -s fontello.css _fontello.scss
app/www/lib/fontello/css $ sed -i '#../font/#../lib/fontello/font/#' fontello.css
 
$ vi app/scss/ionic.app.scss
# 在 @import ionic 之后
// import extend icons from fontello
// @todo but fontello is not sass, need to update "path" once updated
// ../font/ -> ../lib/fontello/font/
@import "www/lib/fontello/css/fontello";
 
 
#### 到此结束,以下是注释 ####
# 必须 sed 替换 fontello 的路径,否则会找不到
# ionicon 由于是用 sass,它修改路径的做法是在 ionic.app.scss 中声明
// The path for our ionicons font files, relative to the built CSS in www/css
$ionicons-font-path: "../lib/ionic/fonts" !default;

tips

  • 使用代理:
    • ionic:
      alias ionic="PROXY=http://proxy-mu.intel.com:911 ionic"
    • export
      export http_proxy=http://proxy-mu.intel.com:911
      export https_proxy=http://proxy-mu.intel.com:911
    • 还不行就需修改 cordova
  • 不知道为什么使用 angular 的 $q(function() {}) 会出现 $q is not a function 的错误, 只能用 $q.defer() 的方法. AngularJS: API: $q
    • 而 ionic 中的 $http 好像也不正常, 尝试在 $stateProviderresolve 中使用, 结果返回疑似 response 对象, 而非 resolve 后的结果
    • 之后找了 mgonto/restangular 做 REST 请求, 很好用 LOL LOL LOL LOL
    • 但是 restangular 和 本地 cache 如何配合还未找到 best practice, angular 自身提供 cache (一个介绍: Jason Dobry : Power up Angular's $http service with caching
    • 而 restangular 也是支持 angular 原生的 cache 的
    • 用了 restangular 后,service 应该只是 restangular 的包装,不包含逻辑 (Decoupled Restangular Service)
      // Declare factory
      module.factory('Users', function(Restangular) {
        return Restangular.service('users');
      });
       
      // In your controller you inject Users
      Users.one(2).get() // GET to /users/2
      Users.post({data}) // POST to /users
       
      // GET to /users
      Users.getList().then(function(users) {
        var user = users[0]; // user === {id: 1, name: "Tonto"}
        user.name = "Gonto";
        // PUT to /users/1
        user.put();
      })
  • angular 的 $http 请求默认 accept: 'application/json, text/plain, */*' , 而 express 可用 res.format 来实现一个 controller 对 web/API 返回不同数据的功能
    res.format({
      text: function(){
        res.send('hey');
      },
     
      html: function(){
        res.send('hey');
      },
     
      json: function(){
        res.send({ message: 'hey' });
      }
    });
  • 如果要列表显示很多数据 (如通讯录), 则应使用 Collection Repeat
  • 模板使用 <script type=“text/ng-template” id=“page-name”> will add the template to the template cache, and save us the request
  • ActionSheet 是针对某个条目弹出的操作(action)列表(sheet)的 widget Understanding Action Sheets | Formulas | Learn Ionic
  • ionic 使用多级 nested state 可参考 Build an App with Navigation and Routing - Part 2 | Formulas | Learn Ionic, 可直接看教程最底部的 Scratchpad:
  • 使用 UI router 时有以下一些 best practice
    • 在 view 中使用 ui-sref 而非 href
    • 使用 <ion-tabs> 布局时, 每个 <ion-tab> 中都要是一个有 name 的 <ion-nav-view name=“tab-foo”>
  • <ion-tabs> 在进入 tab 的深层页面隐藏 tab-bar 可使用 ng-class=“{'tabs-item-hide': notFrontPage()}”
  • 关于 iphone 到底要用 320px 还是 640px
    • 物理设备的尺寸是 320px,所以 layout 的设计需要在 320px 的标准下设计 What screen size should we use for iOS app? - Ionic
    • 但是 retina 技术使得 1px 可以显示 2px 的内容,所以 图片 等资源需要用 640px 的标准
    • 反正我的理解是这样,暂未找详细资料 — Xiaopei Li 2014/08/22 07:03
    • 成哥之前的做法是在 layout 中使用 em,而不同 platform 设置 em 为不同的 px
  • iphone ‘’add to screen‘’ 不显示 safari 地址栏和导航栏
    <meta name="apple-mobile-web-app-capable" content="yes"/>
  • flash message: angular/ionic 中没有类似 rails 的全局 flash notice message 功能,实现可参考以下方法
      • 这个例子只是显示 loading indicator,做法如下
        1. <ion-header-bar class="bar-positive">
            ...
          </ion-header-bar>
           
          <!-- 在 header 和 content 间加一个 loading-bar,在 isLoading 时显示 -->
          <div class="bar bar-loading bar-assertive" ng-if="data.isLoading">
            Loading...
          </div>
           
          <!-- content 在 isLoading 时增加 class -->
          <ion-content ng-class="{'has-loading': data.isLoading}">
            ...
          </ion-content>
        2. .has-header.has-loading {
            /* 44px (header) + 24px(loading bar) */
            top: 68px;
          }
    • wmluke/angular-flash 是 angular modules 中最流行的 flash module
      • 优点:采用 pub/sub 模式,定义了一系列消息类型,不同的 directive 可显示不同类型的消息
      • 缺点:紧耦合 bootstrap,包含一系列动画效果,无法直接在 ionic 中使用,无法自定义样式
      • 可以说是上种方法的简易版,使用 service 包装了 flash,实现了 pub/sub 模型,消息是队列,route 改变时清空
  • ionic-cli v1.2.5 升级 ionic 的 ionic lib update 命令是坏的
  • bower install some-package 会同时把 bower.json 中的其他 packages 都 install 了,不该这样,但原因没找到。如果要 干净地bower install,可以先删除 bower.json
  • 如果需要将数据 按行列 填入表格显示 (row, column),则应数据与逻辑分离,先 在 controller 里 或 在 view 里用 filter 将原始数据 partition,再在 template ng-repeat rowng-repeat col。参考:angularjs - how to split the ng-repeat data with three columns using bootstrap - Stack Overflow
  • 使用 ng-pattern 做验证(像验证 email 时),会出现一输入就报错的问题。一般有两种方法解决

Google Analytics

GA 的用法见 ga

安装

  1. 加载这两个脚本
  2. 在 angular 中配置
    angular.module('myApp', [
      'angulartics', 
      'angulartics.google.analytics'
    ]);
  3. 在 index.html 中还是要加载 GA 脚本
          ...
          ga('create', 'UA-XXXXXXXX-X', 'none'); // 'none' while you are working on localhost
          ga('send', 'pageview');  // 删除这行!
        </script>
  4. angulartics 会自动处理 SPA 的路由,看 GA 已经有数据了

AngularUI Router

Ionic(ion-nav-view) uses the AngularUI Router module so app interfaces can be organized into various “states”.

ion-nav-view is equivalent to ui-view. On top of that, ion-nav-view provides for animations, history, and more.

The simplest form of state

<!-- in index.html -->
<body ng-controller="MainCtrl">
<section ui-view></section>
</body>
// in app-states.js (or whatever you want to name it)
$stateProvider.state('contacts', {
  template: '<h1>My Contacts</h1>'
})

When a state is activated, its templates are automatically inserted into the ui-view of its parent state's template.

how to activate a state

There are three main ways to activate a state:

  • Call $state.go(). High-level convenience method.
  • Click a link containing the ui-sref directive.
  • Navigate to the url associated with the state.

templates configuration

$stateProvider.state('contacts', {
  // 可以返回内容
  template: '<h1>My Contacts</h1>'
  // or
  templateProvider: function ($timeout, $stateParams) {
    return $timeout(function () {
      return '<h1>' + $stateParams.contactId + '</h1>'
    }, 100);
  }
  // 也可以返回模板 URL
  templateUrl: 'contacts.html'
  // or
  templateUrl: function ($stateParams){
    return '/partials/contacts.' + $stateParams.filterBy + '.html';
  }
})

controllers configuration

$stateProvider.state('contacts', {
  template: ...,
  // define a controller
  controller: function($scope){
    $scope.title = 'My Contacts';
  }
  // a defined controller
  controller: 'ContactsCtrl'
  // controllerAs syntax
  controller: 'ContactsCtrl as contact'
  // dynamically return a controller function or string
  controllerProvider: function($stateParams) {
      var ctrlName = $stateParams.type + "Controller";
      return ctrlName;
  }
})

resolve

另外有一种写法, 是通过 resolve (一个 keyfactory 的 mapping) 加载若干依赖/调用若干服务 (typical usage 是 factory 用 promise). 而 controller 只是做一个 “依赖到 $scope 的 mapping”. 详见 wiki#resolve. 很好用 LOL LOL LOL LOL LOL LOL 示例如下:

$stateProvider.state('myState', {
      resolve:{
 
         // Example using function with simple return value.
         // Since it's not a promise, it resolves immediately.
         simpleObj:  function(){
            return {value: 'simple!'};
         },
 
         // Example using function with returned promise.
         // This is the typical use case of resolve.
         // You need to inject any services that you are
         // using, e.g. $http in this example
         promiseObj:  function($http){
            // $http returns a promise for the url data
            return $http({method: 'GET', url: '/someUrl'});
         },
 
         // Another promise example. If you need to do some 
         // processing of the result, use .then, and your 
         // promise is chained in for free. This is another
         // typical use case of resolve.
         promiseObj2:  function($http){
            return $http({method: 'GET', url: '/someUrl'})
               .then (function (data) {
                   return doSomeStuffFirst(data);
               });
         },        
 
         // Example using a service by name as string.
         // This would look for a 'translations' service
         // within the module and return it.
         // Note: The service could return a promise and
         // it would work just like the example above
         translations: "translations",
 
         // Example showing injection of service into
         // resolve function. Service then returns a
         // promise. Tip: Inject $stateParams to get
         // access to url parameters.
         translations2: function(translations, $stateParams){
             // Assume that getLang is a service method
             // that uses $http to fetch some translations.
             // Also assume our url was "/:lang/home".
             return translations.getLang($stateParams.lang);
         },
 
         // Example showing returning of custom made promise
         greeting: function($q, $timeout){
             var deferred = $q.defer();
             $timeout(function() {
                 deferred.resolve('Hello!');
             }, 1000);
             return deferred.promise;
         }
      },
 
      // The controller waits for every one of the above items to be
      // completely resolved before instantiation. For example, the
      // controller will not instantiate until promiseObj's promise has 
      // been resolved. Then those objects are injected into the controller
      // and available for use.  
      controller: function($scope, simpleObj, promiseObj, promiseObj2, translations, translations2, greeting){
          $scope.simple = simpleObj.value;
 
          // You can be sure that promiseObj is ready to use!
          $scope.items = promiseObj.items;
          $scope.items = promiseObj2.items;
 
          $scope.title = translations.getLang("english").title;
          $scope.title = translations2.title;
 
          $scope.greeting = greeting;
      }
   })

Attach Custom Data to State Objects

// Example shows an object-based state and a string-based state
var contacts = { 
    name: 'contacts',
    templateUrl: 'contacts.html',
    data: {
        customData1: 5,
        customData2: "blue"
    }  
}
$stateProvider
  .state(contacts)
  .state('contacts.list', {
    templateUrl: 'contacts.list.html',
    data: {
        customData1: 44,
        customData2: "red"
    } 
  })
 
// In any controller you could access the data like this:
function Ctrl($state){
    console.log($state.current.data.customData1) // outputs 5;
    console.log($state.current.data.customData2) // outputs "blue";
}  

events

  • 每个 state 都有 onEnter and onExit callbacks
  • State Change Events
    • $stateChangeStart fired when the transition begins.
    • $stateNotFound - v0.3.0 - fired when a requested state cannot be found using the provided state name during transition.
    • $stateChangeSuccess - fired once the state transition is complete.
    • $stateChangeError - fired when an error occurs during transition.
  • View Load Events
    • $viewContentLoading - fired once the view begins loading, before the DOM is rendered. The $scope broadcasts the event.
    • $viewContentLoaded - fired once the view is loaded, after the DOM is rendered. The $scope of the view emits the event.

CSS

CSS Components - Ionic Framework

  • Header
  • Content
  • Footer
  • Buttons
  • List
  • Cards
  • Forms
  • Toggle
  • Checkbox
  • Radio Buttons
  • Range
  • Select
  • Tabs
  • Grid
  • Utility

javascript (1.0.0-beta.11)

Javascript - Extend Ionic even further with the power of AngularJS - Ionic Framework

  • Tabs
    • ion-tabs
    • ion-tab
    • $ionicTabsDelegate
  • Side Menus
    • ion-side-menus
    • ion-side-menu-content
    • ion-side-menu
    • menu-toggle
    • menu-close
    • $ionicSideMenuDelegate
  • Navigation
    • ion-nav-view
    • ion-view
    • ion-nav-bar
    • ion-nav-buttons
    • ion-nav-back-button
    • nav-clear
    • $ionicNavBarDelegate
  • Headers/Footers
    • ion-header-bar
    • ion-footer-bar
  • Content
    • ion-content
    • ion-refresher
    • ion-pane
  • Scroll
    • ion-scroll
    • ion-infinite-scroll
    • $ionicScrollDelegate
  • Lists
    • ion-list
    • ion-item
    • ion-delete-button
    • ion-reorder-button
    • ion-option-button
    • collection-repeat
    • $ionicListDelegate
  • Form Inputs
    • ion-checkbox
    • ion-radio
    • ion-toggle
  • Slide Box
    • ion-slide-box
    • $ionicSlideBoxDelegate
  • Modal
    • $ionicModal
    • ionicModal
  • Popover
    • $ionicPopover
    • ionicPopover
  • Action Sheet
    • $ionicActionSheet
  • Popup
    • $ionicPopup
  • Loading
    • $ionicLoading
    • $ionicLoadingConfig
  • Platform
    • $ionicPlatform
  • Events
    • on-hold
    • on-tap
    • on-touch
    • on-release
    • on-drag
    • on-drag-up
    • on-drag-right
    • on-drag-down
    • on-drag-left
    • on-swipe
    • on-swipe-up
    • on-swipe-right
    • on-swipe-down
    • on-swipe-left
  • Gesture
    • $ionicGesture
  • Backdrop
    • $ionicBackdrop
  • Position
    • $ionicPosition
  • Utility
    • ionic.Platform
    • ionic.DomUtil
    • ionic.EventController
  • Tap & Click
  • Keyboard
    • Keyboard
    • keyboard-attach

container

basics of angularjs

How to Learn AngularJS - Your AngularJS Sherpa | ng-newsletter

basics of Angular can be broken down into 5 major components:

  • Directives
  • Controllers
  • Scopes
  • Services
  • Dependency Injection

核心概念: Directives

what is directive?

  • A directive is simply a function that we run on a DOM element to give it added functionality. Directives make it possible to extend HTML with our own functionality
  • All of the ng- tags and attributes are Angular provided directives.
  • ngClick in js and ng-click in HTML refer to the same thing, the idea is that it makes each code look better in context.

what directive to use?

how to write new directives?

  • four methods for invoking a directive
    • As an attribute: <span my-directive></span>
    • As a class: <span class="my-directive: expression;"></span>
    • As an element: <my-directive></my-directive>
    • As a comment: <!-- directive: my-directive expression -->

How Angular Boots, Modules, Scopes, Controllers, Dependency Injection, Services

  1. When we include the Angular javascript into our HTML page, it will attach a method to the DOMContentLoaded event (this means that Angular will run when the page is done loading).
  2. When the page has loaded, Angular will visit every element in your HTML document (i.e. it will traverse every element in the DOM).
  3. The very first directive Angular needs to find is the ngApp directive. Angular will bind our application to the element where it finds the ngApp directive.
  4. Angular only applies functionality to child elements of ngApp.
  5. 一个 ngApp 对应一个 angular.module()
  6. angular.module() 有 setter/getter 两种用法
    1. setter: angular.module('myApp', []);
    2. getter: angular.module('myApp');
    3. 两者都返回 module 对象, chainable
  7. scopes: AngularJS uses scopes to communicate between components - particularly between our javascript and our HTML. Scopes are the glue between our code and what the browser renders. $scope variable 可实现双向绑定
    angular.module('myApp', [])
    .run(function($rootScope) {
      $rootScope.user = {
        email: 'ari@fullstack.io'
      };
      $rootScope.message = "Welcome back";
    });
     
    // html
    //  <input type="text" ng-model="message" placeholder="Enter a message" />
    //  <h3>{{ message }} {{ user.email }}</h3>
  8. module.run() 的 cb 设置了 $rootScope
    angular.module('myApp', [])
    .run(function($rootScope) {
      // ...
    }
  9. 但要避免过度使用 $rootScope. Scope objects can be nested. Angular creates scopes in a variety of situations. For instance, a child scope is created for every controller.
  10. A controller is code that ties models to views using scopes
    1. html
      <body ng-app='myApp'>
        <!-- We have access to the $rootScope here -->
        <h1>Welcome back {{ user.name }}</h1>
        <div ng-controller='HomeController'>
          <!-- 
            in here, the $scope object of the HomeController will be used, 
            but we still have access to the $rootScope object
          -->
          The HomeController thinks your name is {{ user.name }}, while the $rootScope thinks it's {{ $parent.user.name }}.
        </div>
      </body>
    2. js
      angular.module('myApp', [])
      .run(function($rootScope) {
        $rootScope.user = {
          name: 'Ari'
        };
      })
      .controller('HomeController', function($scope) {
        $scope.user = {
          name: 'Nate' 
        };
      });
    3. view
      Welcome back Ari
      
      The HomeController thinks your name is Nate, 
      while the $rootScope thinks it's Ari. 
  11. 以上是 angular 的 view 和 controller. 那 angular 怎么实现 model 的呢? 用 $http !
  12. Angular comes bundled with a wrapper around the XMLHttpRequest (also known as XHR, which is how you perform AJAX) called $http.
  13. Angular 还集成 Promise 处理 async 操作:
    promise
    .then(function(data) {
      // Called when no errors have occurred with data
    })
    .catch(function(err) {
      // Called when an error has occurred
    })
    .finally(function(data) {
      // Called always, regardless of the output result
    })
  14. Dependency Injection / annotating
    1. angular 设置 controller 依赖关系的方法叫做 annotating
      angular.module('myApp', [])
      .controller('HomeController', function($scope, $q) {
        // We have the $scope object and the $q object
        // available in here
      });
    2. 需要注意 .controller() 设置的 function() 并不是 node.js 常用的 cb 模式, 而就是在定义一个 controller, function() 的参数描述了 DI 关系, 而不是特定的 cb 的参数顺序
    3. The names have to match an existing object. 这就分为了 自定义的 和 built-in 的模块
    4. The module you want to use has to be required into the current module
      // say we have some services...
      angular.module('fullstack.services', [])
        // some code that defines services here
        .service('WeatherService', function() {
          // define the weather service here
        });
      );
       
      // and we want to use those services in our controllers
      angular.module('fullstack.controllers', ['fullstack.services'])
        // now we have WeatherService available
      );
    5. $scope, $q 是 Angular built-ins so they’re already included
    6. 但是普通 annotation 写法没法 minify, inline annotation 才能 minify, olov/ng-annotate 可用来转换两类写法
      // 普通 annotation, 不能被 minify
      .controller('HomeController', function($q, $scope) {
       
      // inline annotation, 可被 minify
      .controller('HomeController', ['$scope', '$q', function($scope, $q) {
  15. Services are singleton objects that perform tasks common to several areas of the system.
  16. service 一般定义在 module 中, module annote/DI module, controller annote/DI service
it/ionic.txt · Last modified: 2015/12/09 10:43 by admin