Angular单页应用动态切换页面标题

Background

在运行angular单页应用的时候,有时候需要能够动态的根据当前的view来切换当前的标题.
JavaScript原生语法中,其实是可以直接利用document.title='xxx'来实现.

但是根据Kary Gor的建议,所有原生的DOM操作其实都建议在directive中进行.
所以参考StackOverFlow上的一个做法,实现动态切换当前页标题.

Solution

总体的实现步骤分为以下几步:

  1. 建立一个factory用于控制当前页标题
  2. 建立一个controller,专门用于控制最上级html的header部分的操作
  3. 在其他子controller,调用更变页面标题的方法

创建pageService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/** Services for html page such as Header */

var angular = require('angular');
//noinspection JSCheckFunctionSignatures
var $injector = angular.injector(['ng']);
var $log = $injector.get('$log');
var _ = require('lodash');

var pageService = function pageService(){
var svc = this;
svc.defaultTitle = 'Aquariuslt Home';
svc.title = svc.defaultTitle;

function getTitle(){
return svc.title;
}

function setTitle(newTitle){
if(!_.isEmpty(newTitle)){
svc.title = newTitle + ' - ' + svc.defaultTitle;
}
else{
svc.title = svc.defaultTitle;
}
$log.info('set new title:',svc.title);
}

return{
getTitle:getTitle,
setTitle:setTitle
};
};

module.exports = pageService;

创建pageController

page-controller.js:

1
2
3
4
5
6
var pageService = require('../services/page-service')();

module.exports = function pageController(){
var page = this;
page.service = pageService;
};

index.html:

在html标签直接添加一个controller作为scope.
一开始是直接在<title></title>标签内直接使用page.service.getTitle()的.
但是发现在angular还没有加载完成的时候,默认的标题 会显示成这个表达式本身的字符串,非常丑陋.
于是用了ng-bind去绑定.在angular数据绑定还没生效的时候,使用原来的默认标题.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en" ng-app="home" ng-controller="pageController as page">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="http://blog.aquariuslt.com/images/avator.png">
<base href="#">
<title ng-bind="page.service.getTitle()">Aquariuslt Home</title>
<!-- Load CSS Bundles Here -->
<!-- CSS -->
</head>
<body>
<header ng-include="'app/common/views/header.html'"></header>
<ui-view></ui-view>
<!-- Load JavaScript Bundles Here -->
<!-- JS -->
</body>
</html>

其他子controller的调用方法

比如我有一个tag页面:
http://aquariuslt.com/#/tag/Java

我需要将当前页面的标题前缀加上Tag Contains Java
则需要在这个页面的controller中这样调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
var pageService = require('../../common/services/page-service')();
var articleService = require('../services/article-service')();

module.exports = function tagController($stateParams,$interval){
var vm = this;

vm.atomList = [
"http://blog.aquariuslt.com/atom",
"http://debug.aquariuslt.com/atom",
"http://game.aquariuslt.com/atom"
];
vm.tagName = $stateParams.tagName;
vm.indeterminateValue = 0;
vm.showProgressBar = false;
vm.tagDetailList = [];

init();

function init(){
initTitle();
loadTagDetail();
}

function initTitle(){
pageService.setTitle('Tags Contains '+vm.tagName);
}

function loadTagDetail(){
startInterval();
articleService.loadArticleSummaryList(vm.atomList,function(error,summaryList){
vm.tagDetailList = articleService.filterArticleListByTagName(summaryList,vm.tagName);
stopInterval();
});
}

function updateProgressBar(){
if(vm.showProgressBar){
vm.indeterminateValue += 1;
if (vm.indeterminateValue > 100) {
vm.indeterminateValue = 0;
}
}
}

function startInterval(){
vm.showProgressBar = true;
$interval(updateProgressBar, 100, 0, true);
}

function stopInterval(){
vm.showProgressBar = false;
$interval.cancel(updateProgressBar);
}

};
Compartir Comentarios

关于document.createElement的图片加载问题

Background

最近在更新网站首页的时候,在实现文章摘要结果的时候,采用了不太正当的方法导致加载时间过长.

在获取文章Summary的时候,原本Summary的样式应该是这样子的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<entry>
<title>
<![CDATA[ Angular Material md-button 不全部大写 ]]>
</title>
<link href="http://debug.aquariuslt.com/2016/03/20/angular-material-md-button-using-lowercase/"/>
<id>
http://debug.aquariuslt.com/2016/03/20/angular-material-md-button-using-lowercase/
</id>
<published>2016-03-20T07:33:50.000Z</published>
<updated>2016-03-22T05:42:44.939Z</updated>
<content type="html">
</content>
<summary type="html">
<![CDATA[
<h2 id="BackGround"><a href="#BackGround" class="headerlink" title="BackGround"></a>BackGround</h2><p>刚刚接触<code>Angular-Material</code>,发现其<
]]>
</summary>
</entry>

在获取Summary的时候,由于summary的片段是不完整的html标签字符串,根本没有终止符,无法合理的转化成摘要文字.

于是我就直接将content里面的全文html字符串来截取摘要内容.
如何合理的截取到html字符串里面的innerText呢?
一开始就使用了document.createElement()方法:
通过将html字符串来创建一连串的dom element,然后用innerText来获取去除html标签之后的内容.

1
2
3
4
5
function handleArticleSummary(articleSummary){
var div = document.createElement("div");
div.innerHTML = articleSummary.content._;
articleSummary.content.text = div.innerText;
}

但是这样就会导致 html 里面的 img 标签和以前涉及网络加载的标签,会在随着createElement()后的赋值方法,去获取实际上的img内容.
加载图片或者其他脚本.这样导致第一次加载的时候耗时过长.

Solution

目前还没有正统的解决办法,我是使用正则表达式匹配img标签,将img标签过滤掉.
来达到不必加载的目的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Get innerText from html body.
* When using document.createElement(htmlString),
* which htmlString contains image link, will load image from its src.
* it will cause much network time,so replace the image link.
* */

function handleArticleSummary(articleSummary){
var imageLinkRegex = /<img\s[^>]*?src\s*=\s*['"]([^'"]*?)['"][^>]*?>/ig;
var originalHtmlString = articleSummary.content._;
var convertedHtmlString = originalHtmlString.replace(imageLinkRegex,'');
var div = document.createElement("div");
div.innerHTML = convertedHtmlString;
articleSummary.content.text = div.innerText;
}
Compartir Comentarios

IntelliJ IDEA 不能正常解析Node.js Core Modules 属性方法的解决方案

Background

IntelliJ IDEA更新到2016.01之后,在使用Node.js的原生API的时候,遇到了了一个问题:
不能够auto-complete出对应的属性方法:
比如以下的代码:

1
2
3
var filePath = '/home/aquariuslt/Downloads/avator.png';
var path = require('path');
path.basename(filePath);

正常情况下是能够根据Node.js的API预定义文件core_moudles对方法名进行自动补全.
正常情况

更新之后居然不能自动提示了

Solutions

有两个解决方案,分别对应不同的情况.
两个都试过了,分别在Windows,Linux下完成

重新Enable一次Node.js Framework Support

File->Settings->Languages & Frameworks
先disable掉Node.js
再enable.

Languages & Frameworks Settings

如果安装过不同版本的Node.js,删除不同版本的IDEA Node.js 定义文件

在User的个人目录~
可能存放了不同IDEA版本,不同Node.js版本的配置文件

1
2
3
4
5
$ls -al | grep Idea

C:\Users\CUIJA>ls -al | grep Idea
drwxr-xr-x 1 CUIJA 1049089 0 Mar 21 18:38 .IntelliJIdea15
drwxr-xr-x 1 CUIJA 1049089 0 Mar 21 18:42 .IntelliJIdea2016.1

先删除旧的IDEA 版本的config文件夹.
再进入当前使用的IDEA版本的config文件夹

1
2
3
4
5
6
$cd .IntelliJIdea2016.1\config\javascript\nodejs
total 0
drwxr-xr-x 1 CUIJA 1049089 0 Mar 21 18:47 .
drwxr-xr-x 1 CUIJA 1049089 0 Mar 21 18:47 ..
drwxr-xr-x 1 CUIJA 1049089 0 Mar 21 18:47 4.3.1
drwxr-xr-x 1 CUIJA 1049089 0 Mar 21 18:47 4.4.0

删掉那个比较旧的文件夹 即可.

Compartir Comentarios

Angular Material md-button 不全部大写

BackGround

刚刚接触Angular-Material,发现其md-button指令是内文本全大写

Solution

在CSS里面添加

1
2
3
4
/** For md-button lowercase using lowercase */
.md-button {
text-transform: capitalize !important;
}

After Update CSS

Compartir Comentarios

Mac OS X下替换IDEA15自带的JDK

Background

由于最近一直在研究不同版本的JDK/JVM在不同操作系统下的字体渲染.(强迫症)
发现Mac下的IDEA在更新到15之后,字体居然变粗了.
从个人审美的角度看.觉得渲染不是很好看.
通过菜单的About IntelliJ IDEA查看.
发现启动运行IDEA的居然是OpenJDK.
OpenJDK启动IDEA

Solution

解决办法相当简单.
这是因为IDEA的Mac版本,在版本15之后在包内容下自带了个JDK/JRE.
从启动的脚本来说,如果有内置的JDK/JRE,则会调用自带的JDK.

应用程序中右键显示包内容,进入Contents文件夹,删除jre文件夹即可.
删除即可

OracleJDK启动IDEA

Compartir Comentarios

Node.js oracledb "ORA-21561 - OID generation failed" 解决方案

Background

千辛万苦在虚拟机的CentOS 6下编译好oracledb,运行时报错
“ORA-21561 - OID generation failed”

Solution

原因是虚拟机下的CentOS连接到oracle服务器的时候,本地没有有效的连接名称(机器名)
Origin Post

需要在hosts列表中添加本地的机器名.
假设我local机器名为centos-vm

1
sudo gedit /etc/hosts   (vi也行)

查找127.0.0.1 在对应的hostname后面添加centos-vm,即本机器名

修改CentOS hosts文件

重启即可.

Compartir Comentarios

RHEL(CentOS)6环境下安装node-oracledb

Background

最近准备升级一下PROD服务器上的node-oracledb版本.
但是遇到一个很奇怪的现象,就是我本地无法构建出服务器上可用的oracledb.
(因为部署方式是打包部署而不是从git拉代码部署)

一开始以为是C++运行库的原因.
因为又仔细读了一遍node-oracledb的官方安装文档,发现oracledb在编译的时候,只支持支持C++11的编译器.

立马查看本地环境的gcc版本与运行库版本glibc

1
2
gcc -v
ldd --version

发现本地CentOS 6.6版本自带的gcc版本是4.4,glibc版本是2.12
但是支持编译和运行C++11新特性的gcc版本是4.7+,glibc版本是2.14+
这.版本都不一样怎么玩.

RootCause

马上比较了一下 本地构建oracledb与服务器的各种版本
发现相关的版本信息如下:

服务器
OS:RedHat Enterprise Linux 6.6
gcc Version:4.4 (Red Hat)
glibc Version:2.12
node Version:v0.10.38
npm Version:1.4.28(npm版本应该不会影响构建,预防万一还是提及一下)
node-gyp Version:不明.因为没权限调用该命令.
oracle instantclient Version:11.2

本地环境
OS:CentOS 6.7 x64
gcc Version:4.4 (Red Hat)
glibc Version:2.12
node Version:v4.2.4
npm Version:2.14.8
node-gyp Version:3.2.1
oracle instantclient Version:11.2

Solution

思前想后,想想也不知道node.js本身版本到底会对oracledb的构建有什么影响.
毕竟oracledb官方对构建时的C++11编译支持的要求先入为主了

最后还是决定先切换一下node.js版本,结果问题顺利解决

1
2
3
$npm install n
$n v0.10.38
$npm install oracledb

构建成功.

Compartir Comentarios

Linux "libxx cannot open shared object file no such file or directory"解决方案

This is a patch/enhancement about http://debug.aquariuslt.com/2015/12/14/libclntsh-so-11-1-cannot-open-shared-object-file/

Description

I was install Ubuntu 15.10 for tasting the new version of Ubuntu.
After setting up MEAN development and run node.js program.

Node.js throw error belows:

libaio.so cannot open shared object file no such file or directory

I try to find this in oracle instant client directory, but there is no file named this in it.
Then I power on the Ubuntu 14.04 and type command

1
locate libaio.so

It can be found in /lib/x86_64_linux_gnu
But not found in UBuntu 15.10

RootCause

That’s because Ubuntu 15.10 use different gnu/g++ version from Ubuntu 14.04.

Solution

You can follow these steps to locate the root cause and solve it.

  1. Using command locate {filename} to search .so file.
    If result is empty, you can try below;

  2. Install the *.so file.
    Using command

    1
    sudo apt-get install {filename without .so}

or

If you found there is the same filename prefix but with version number,
for example,the error tips libaio.so not found, but you found there is a file named libaio.so.11.2 in /lib/x86_64_linux_gnu
you can make a softlink
using command

1
2
ln -s libaio.so.11.2 libaio.so
sudo updatedb

Compartir Comentarios

Linux 虚拟机Ubuntu扩容

Description

一时大意,本以为vmware下的虚拟机可以随便调整磁盘容量,于是在给有1T SSD的服务器建立Ubuntu虚拟机镜像的时候很傻比的只分了40G的最大容量.
没想到开发环境用的DB日渐增长,磁盘空间竟然很快消耗殆尽.

于是赶紧给通过vmware的虚拟机硬件设置给将最大磁盘空间升级到120G(依然很小气- -)

突然想起 Linux 的磁盘挂载方式 不大一样.上网找了一些类似的解决方案之后,都发现不太好记.

Solution

通过Ubuntu下的一个GUI软件,叫gparted,能够图形化的类似Windows下的磁盘管理工具一样,进行磁盘空间的重新划分与转移.

在本次使用gparted进行分区转移,大概分成以下几步:

  1. 安装并运行gparted
  2. 删除Ubuntu下原本的extend分区及linux swap空间
  3. 对原有磁盘空间进行扩容
  4. 新建extend分区,建立linux swap空间

安装并运行gparted

1
2
$sudo apt-get install gparted
gparted

gparted界面

删除Ubuntu下原本的extend分区及linux swap空间

这里提及一下之前有的错误做法
我一开始的做法是,直接给未格式化的空间,格式化之后,作为一个新的磁盘挂载在系统中
这样,需要对 /media/${username}/新空间名称 进行一个链接
才能达到扩容的目的.
感觉这样相当不优雅.像是乱插了N个奇形怪状的U盘在身上

研究后发现,Linux的Swap空间阻断了分区扩容,在磁盘起始点和终点上不连续.
所以先右键File Systemextend的分区,删除之

对原有磁盘空间进行扩容

删除extend的空间之后,便可以对原有的/dev/sda1进行扩容.
此时右键/dev/sda1选择resize,在保证预留出大小相当于分配给虚拟机的内存的空间的情况下,分多点~
点击apply生效

新建extend分区,建立linux swap空间

最后,重新建立linux swap空间.
对着还未分配的空间,新增一个file systemextended的扩展分区,apply之.
然后在该分区下新建一个linux-swap空间.

扩容后截图

Compartir Comentarios

Linux "libclntsh.so.11.1 cannot open shared object file no such file or directory"解决方案

Description

Ubuntu 14.04
node v4.2.3
oracledb v1.4.0
在正常安装好Node.jsoracledb,之后,用到oracledb的那一步就开始提示这个错误;
重新跑npm install不能解决问题

RootCause

LD_LIBRARY_PATH没有设置好.
我将OracleInstantClient的安装目录的路径,释放在当前用户的环境变量中.
即将export LD_LIBRARY_PATH=XXXX写在当前user的.bashrc
导致terminal中启动的时候,读不到LB_LIBRARY_PATH变量.
如果运行如下命令,没有设置环境变量的话,可以通过该解决方案解决.

1
locate libclntsh.so.11.1

Solutions

将环境变量设置在/etc/profile中,问题解决.

Compartir Comentarios