ãã®èšäºã§ã¯ã AngularJSãKnockoutãªã©ã®ãã¬ãŒã ã¯ãŒã¯ã§ã®ç§ã®çµéšãå ±æããããšæããŸãã
ãã®èšäºã¯ãJavaScriptã«ç²ŸéããŠãããèšåããããã¬ãŒã ã¯ãŒã¯ã®å°ãªããšã1ã€ã«ã€ããŠã¢ã€ãã¢ãæã¡ãåœç¶ãªããèŠéãåºããã人ã«ãšã£ãŠèå³æ·±ããã®ã«ãªããŸãã
埩ç¿
AngularJSãšKnockoutã®ã€ããªãã®ãŒã¯éåžžã«äŒŒãŠããŸãã ãããã¯åçWebã¢ããªã±ãŒã·ã§ã³ã®ãã¬ãŒã ã¯ãŒã¯ã§ãããHTMLããã³ãã¬ãŒããšããŠäœ¿çšããŸãã ã¢ããªã±ãŒã·ã§ã³ã®ã³ã³ããŒãã³ããããæ確ãã€ç°¡æœã«èšè¿°ããããã«ãHTMLæ§æãæ¡åŒµã§ããŸãã ããã«ãmodel-view-controller.AngularJSãšKnockoutã®éä¿¡ãå®è£ ããããã«ä»¥åã«äœæãããã³ãŒããèšè¿°ããå¿ èŠããªããªããŸã-ããã¯ãçŸä»£ã®Webã¢ããªã±ãŒã·ã§ã³ãäœæããããã«èšèšãããå Žåãåºæ¬çã«HTMLãšJavaScriptã§ãã HTMLã¯ãéçããã¥ã¡ã³ãçšã®åªãã宣èšåèšèªã§ãã ããããæ®å¿µãªãããææ°ã®Webã¢ããªã±ãŒã·ã§ã³ãäœæããããã«å¿ èŠãªãã®ã¯ããŸããããŸããã
ç¹åŸŽ
- ããŒã¿ãã€ã³ãã£ã³ã°ïŒUIãšããŒã¿ã¢ãã«ããªã³ã¯ããããã®ã·ã³ãã«ã§åªããæ¹æ³ã
- éçºè åãã®åŒ·åãªããŒã«ã»ããïŒç¹ã«AngularJSã§ã¯ãKnockoutã®ã»ããã¯ããªã貧匱ã§ãïŒ
- ç°¡åã«æ¡åŒµå¯èœãªããŒã«ããã
ã¢ããªã±ãŒã·ã§ã³ã¢ãŒããã¯ãã£
ããã¥ã¡ã³ãã«ãããšãAngularã¯ã¢ããªã±ãŒã·ã§ã³ãã¢ãžã¥ãŒã«ã«åå²ããŠæ§é åããããšãææ¡ããŠããŸãã åã¢ãžã¥ãŒã«ã®æ§æã¯æ¬¡ã®ãšããã§ãã
- ã¢ãžã¥ãŒã«ãæ§æããæ©èœ-ã¢ãžã¥ãŒã«ãããŒãããçŽåŸã«éå§ããŸãã
- ã³ã³ãããŒã©ãŒ
- ãµãŒãã¹;
- ãã£ã¬ã¯ãã£ãã
é çªã«ãKnockoutã¯ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããModelViewã«åå²ããŸããModelViewã¯ãã¢ãã«ãšã³ã³ãããŒã©ãŒã®æ··åã§ãã ko.bindingHandlersãªããžã§ã¯ãå ã«ã¯ãAngularãã£ã¬ã¯ãã£ãã«é¡äŒŒããããŒã¿ãã€ã³ãã£ã³ã°ããããŸãã ObservableãšobservableArrayã¯ãã¢ãã«ãšãã®è¡šçŸã®éã®é¢ä¿ãæ§ç¯ããããã«äœ¿çšãããŸãã
ã¢ãžã¥ãŒã«æ§ã«ã€ããŠèšãã°ãAMDãã³ãã¬ãŒã-éåæã¢ãžã¥ãŒã«å®çŸ©ãæãåºããŸããã AngularãšKnockoutã«ã¯ãç¬èªã®AMDãã³ãã¬ãŒãå®è£ ããããŸããã RequireJSã©ã€ãã©ãªã䜿çšããããšããå§ãããŸãã 圌女ã¯ãAngularãšKnockoutã®äž¡æ¹ãšã®äºææ§ã«é¢ããŠéåžžã«ãã蚌æãããŠããŸãã ããã«é¢ããããèå³æ·±ãæ å ±ã¯ã http ïŒ //www.kendoui.cââom/blogs/teamblog/posts/13-05-08/requirejs-fundamentals.aspxããã³http://habrahabr.ru/post/152833/ã«ãããŸãã
ãã³ãã¬ãŒãäœæ

ïŒAngularJSéçºè ã®ãã®ãããªçŸããåçã«æè¬ããŸãïŒ
çŸæç¹ã§ã¯ããã§ã«èšå€§ãªæ°ã®ãã³ãã¬ãŒããšã³ãžã³ããããŸãã ããšãã°ãjQueryãã³ãã¬ãŒãïŒæ®å¿µãªããããµããŒããããªããªããŸããïŒã ãããã®ã»ãšãã©ã¯ãéçãã³ãã¬ãŒããæååãšããŠåãåããããŒã¿ãšæ··åããæ°ããè¡ãäœæããinnerHTMLããããã£ã䜿çšããŠç®çã®DOMèŠçŽ ã«çµæã®æååã貌ãä»ããŸãã ãã®ãããªã¢ãããŒããšã¯ãããŒã¿ãå€æŽãããåŸã«æ¯åãã³ãã¬ãŒããåã¬ã³ããªã³ã°ããããšãæå³ããŸãã ãã®ã¢ãããŒãã«ã¯å€ãã®æ¢ç¥ã®åé¡ããããŸããããšãã°ããŠãŒã¶ãŒå ¥åã®èªã¿åããšã¢ãã«ãžã®æ¥ç¶ãäžæžãã«ãããŠãŒã¶ãŒããŒã¿ã®æ倱ãããŒã¿ããã¬ãŒã³ããŒã·ã§ã³ã®æŽæ°ããã»ã¹å šäœã®ç®¡çãªã©ã§ãã ããã«ãç§ã®èãã§ã¯ããã®ã¢ãããŒãã¯çç£æ§ã«æªåœ±é¿ãåãŒããŸãã
AngularãšKnockoutã¯ç°ãªãã¢ãããŒããåããŸãã ããªãã¡ãåæ¹åãã€ã³ãã£ã³ã°ã ãã®ã¢ãããŒãã®ç¹åŸŽã¯ãããŒãžèŠçŽ ãšã¢ãã«èŠçŽ ã®åæ¹åéä¿¡ã®äœæã§ãã ãã®ã¢ãããŒãã«ãããããªãå®å®ããDOMãååŸã§ããŸãã Knockoutã§ã¯ãobservableããã³observableArrayé¢æ°ã䜿çšããŠåæ¹åéä¿¡ãå®è£ ãããŸãã ãã³ãã¬ãŒããåæããããã«ãjQuery HTMLããŒãµãŒã䜿çšãããŸãïŒæ¥ç¶ãããŠããå Žåããã以å€ã¯åæ§ã®ãã€ãã£ãããŒãµãŒïŒã äžèšã®é¢æ°ã®çµæã¯ãã¢ãã«èŠçŽ ã®çŸåšã®ç¶æ ãã«ãã»ã«åããåæ¹åãã€ã³ãã£ã³ã°ãæ åœããé¢æ°ã§ãã ç§ã®æèŠã§ã¯ããã®å®è£ ã¯ãã¢ãã«ã®ç¶æ ã®ã³ããŒã«é¢é£ããåé¡ããããããããŸã䟿å©ã§ã¯ãããŸãããé¢æ°ã¹ã³ãŒãã¯ã³ããŒãããªããããæåã«ã¢ãã«èŠçŽ ããããŒã¿ãååŸããå¿ èŠãããããããé¢æ°ãšããŠåç §ããŠããçµæãè€è£œããã ãã§ãã
Angularã§ã¯ãåæ¹åéä¿¡ã¯ã³ã³ãã€ã©ïŒ$ã³ã³ãã€ã«ãµãŒãã¹ïŒã«ãã£ãŠçŽæ¥æ§ç¯ãããŸãã éçºè ã¯ãobservableãªã©ã®é¢æ°ã䜿çšããå¿ èŠã¯ãããŸããã ç§ã®æèŠã§ã¯ãè¿œå ã®èšèšã䜿çšããå¿ èŠããªããã¢ãã«èŠçŽ ã®ç¶æ ãã³ããŒãããšãã«åé¡ããªããããããã¯ã¯ããã«äŸ¿å©ã§ãã
AngularãšKnockoutã§ã®ãã³ãã¬ãŒããšã³ãžã³ã®å®è£ ã®äž»ãªéãã¯ãèŠçŽ ã®ã¬ã³ããªã³ã°æ¹æ³ã§ããAngularã¯DOMèŠçŽ ãçæããããã䜿çšããŸãã Knockout-æååãšinnerHTML-itãçæããŸãã ãããã£ãŠãå€æ°ã®èŠçŽ ãçæããã«ã¯ãKnockoutã®æéãããããŸãïŒè¯ãäŸã¯å°ãäœããªããŸãïŒã
ããŒã¿ã¢ãã«
Angularã®ããŒã¿ã¢ãã«ã«ã€ããŠèšãã°ã$ã¹ã³ãŒããµãŒãã¹ã§ééããªãåæ¢ããå¿ èŠããããŸãã ãã®ãµãŒãã¹ã«ã¯ãããŒã¿ã¢ãã«ãžã®ãªã³ã¯ãå«ãŸããŠããŸãã Angularã¯ããªãè€éãªã¢ããªã±ãŒã·ã§ã³ã¢ãŒããã¯ãã£ãæ³å®ããŠããããã$ã¹ã³ãŒããããè€éãªæ§é ã«ãªã£ãŠããŸãã
åã¢ãžã¥ãŒã«å ã§ã$ rootScopeã®åå«ã§ãã$ scopeã®æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæãããŸãã ããã°ã©ã ã«ãããæ¢åã®ã€ã³ã¹ã¿ã³ã¹ãã$ scopeã®æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæããããšãã§ããŸãã ãã®å Žåãäœæãããã€ã³ã¹ã¿ã³ã¹ã¯ããããäœæããã$ã¹ã³ãŒãã®çžç¶äººã«ãªããŸãã JavaScriptãçç¥ããŠãã人ãªããAngularã§$ã¹ã³ãŒãéå±€ãæ±ãã®ã¯ç°¡åã§ãã ãã®æ©èœã¯ããããã¢ãããªã©ã®ããŸããŸãªãŠã£ãžã§ãããäœæããå¿ èŠãããå Žåã«éåžžã«äŸ¿å©ã§ãã
ããŒã¿ãã€ã³ãã£ã³ã°
Knockoutã®ãã€ã³ãã£ã³ã°ãAngularã®ãã£ã¬ã¯ãã£ãã¯ãHTMLæ§æãæ¡åŒµãããããã€ãŸããã©ãŠã¶ãŒã«æ°ããããªãã¯ãæããããã«äœ¿çšãããŸãã ããŒã¿ãã€ã³ãã£ã³ã°ãšãã£ã¬ã¯ãã£ãã®æŠå¿µã«ã€ããŠã¯è©³ããåæããŸããã Knockoutã§ããŒã¿ãšãã¬ãŒã³ããŒã·ã§ã³ãšã®æ¥ç¶ã衚瀺ããã«ã¯ãããŒã¿ãã€ã³ãã£ã³ã°ãå¯äžã®æ¹æ³ã§ããããšã«æ³šæããŠãã ããã
ãã®åé¡ã«ã€ããŠã¯ãèšäºã§è©³ãã説æããŠããŸãã
AngularJSïŒ http ://habrahabr.ru/post/164493/ãhttpïŒ//habrahabr.ru/post/179755/ãhttpïŒ //habrahabr.ru/post/180365/
KnockoutJSïŒ http : //www.knockmeout.net/2011/07/another-look-at-custom-bindings-for.html
ãŸããAngularã®ãã£ã«ã¿ãŒã®ååšã«ã€ããŠãèšåããããšæããŸãã ãã£ã«ã¿ã¯ãç»é¢ã«è¡šç€ºãããããŒã¿ããã©ãŒãããããããã«äœ¿çšãããŸãã æ®å¿µãªãããKnockoutã¯ãã¹ãŠã«ãã€ã³ãã£ã³ã°ã䜿çšããŸãã
äŸ
ãã§ãŒãã€ã³ã¢ãã¡ãŒã·ã§ã³
AngularJSïŒ http : //jsfiddle.net/yVEqU/var ocUtils = angular.module("ocUtils", []); ocUtils.directive('ocFadeIn', [function () { return { restrict: 'A', link: function(scope, element, attrs) { $(element).fadeIn("slow"); } }; }]); function MyCtrl($scope) { this.$scope = $scope; $scope.items = []; $scope.add = function () { $scope.items.push('new one'); } $scope.pop = function () { $scope.items.pop(); } }
ããã¯ã¢ãŠãïŒ http : //jsfiddle.net/fH3TY/
var MyViewModel = { items: ko.observableArray([]), fadeIn: function (element) { console.log(element); $(element[1]).fadeIn(); }, add: function () { this.items.push("fade me in aoutomatically"); }, pop: function () { this.items.pop(); } }; ko.applyBindings(MyViewModel, $("#knockout")['0']);
ãã®äŸãããç°¡åãªãã®ãèŠã€ããã®ã¯é£ãããšæããŸãããã¬ãŒã ã¯ãŒã¯ã®æ§æãå®å šã«ç€ºããŠããŸãã
ãã§ãŒãã¢ãŠãã¢ãã¡ãŒã·ã§ã³
AngularJSïŒ http : //jsfiddle.net/SGvej/ var FADE_OUT_TIMEOUT = 500; var ocUtils = angular.module("ocUtils", []); ocUtils.directive('ocFadeOut', [function () { return { restrict: 'A', link: function(scope, element, attrs) { scope.$watch(attrs["ocFadeOut"], function (value) { if (value) { $(element).fadeOut(FADE_OUT_TIMEOUT); } }); } }; }]); function MyCtrl($scope, $timeout) { this.$scope = $scope; $scope.items = []; $scope.add = function () { $scope.items.push({removed: false}); } $scope.pop = function () { $scope.items[$scope.items.length - 1].removed = true; $timeout(function () { $scope.items.pop(); console.log($scope.items.length); }, FADE_OUT_TIMEOUT); } }
ããã¯ã¢ãŠãïŒ http : //jsfiddle.net/Bzb7f/1/
var MyViewModel = { items: ko.observableArray([]), fadeOut: function (element) { console.log(element); if (element.nodeType === 3) { return; } $(element).fadeOut(function () { $(this).remove(); }); }, add: function () { this.items.push("fade me in aoutomatically"); }, pop: function () { this.items.pop(); } }; ko.applyBindings(MyViewModel, $("#knockout")['0']);
ãã®äŸã¯åã®äŸã»ã©è€éã§ã¯ãããŸããããããã€ãã®ãã¥ã¢ã³ã¹ããããŸãã
Angularã®å ŽåãDOMèŠçŽ ã¯ãã®ã¢ãã«èŠçŽ ã«é¢é£ä»ããããŠãããèŠçŽ ãåé€ããããšããã«åé€ããããããèŠçŽ ãåé€ããåã«fadeOutãå®è¡ããå¿ èŠããããŸãã ãŸããé åããã¢ãã«èŠçŽ ãåé€ããã«ã¯ã$ã¿ã€ã ã¢ãŠããµãŒãã¹ã䜿çšããå¿ èŠãããããšã«æ³šæããããšãéèŠã§ãã ãã®ãµãŒãã¹ã¯ãæ¬è³ªçã«setTimeouté¢æ°ã®ã©ãããŒã§ãããããŒã¿ã¢ãã«ã®æŽåæ§ãä¿èšŒããŸãã
ããã¯ã¢ãŠãã«ã¯å¥ã®åé¡ããããŸãã fadeOuté¢æ°ã¯ãæåã®åŒæ°ãšããŠããã®ã¢ãã«èŠçŽ ã«é¢é£ããDOMèŠçŽ ã®é åãåãåããŸãã å¥åŠãªç¶æ³äžã§ã¯ãã¬ã³ããªã³ã°ããã»ã¹äžã«ãã³ãã¬ãŒããäœæãããããšããããŸãããããã£ãŠãçµæã®é åã«ãã³ãã¬ãŒããååšãããããfadeOutãå®è¡ããåã«èŠçŽ ã確èªããå¿ èŠããããŸãã ãŸããfadeOutããã»ã¹ã®æåŸã«ãDOMèŠçŽ ãåé€ããããšãå¿ããªãã§ãã ããïŒãããã¯èªåçã«åé€ãããŸããïŒã
ãããã¢ãã
AngularJSïŒ http ://jsfiddle.net/vmuha/EvvY7/ãhttpïŒ //angular-ui.github.io/bootstrap/ ïŒ2çªç®ã®ãªã³ã¯ã§ã¯ãå€ãã®åªããæçšãªãœãªã¥ãŒã·ã§ã³ãèŠã€ãããŸãïŒ var ocUtils = angular.module("ocUtils", []); function MyCtrl($scope, $compile) { var me = this; this.$scope = $scope; $scope.open = function (data) { var popupScope = $scope.$new(); popupScope.data = data; me.popup = $("<div class=\"popup\">{{data}}<br /><a href=\"#\" ng-click=\"close($event)\"> Close me</a></div>"); $compile(me.popup)(popupScope); $("body").append(me.popup); } $scope.close = function () { if (me.popup) { me.popup.fadeOut(function () { $(this).remove(); }); } } }
ããã¯ã¢ãŠãïŒ http : //jsfiddle.net/vmuha/uwezZ/ãhttp ïŒ //jsfiddle.net/vmuha/HbVPp/
var jQueryWidget = function(element, valueAccessor, name, constructor) { var options = ko.utils.unwrapObservable(valueAccessor()); var $element = $(element); setTimeout(function() { constructor($element, options) }, 0); //$element.data(name, $widget); }; ko.bindingHandlers.dialog = { init: function(element, valueAccessor, allBindingsAccessor, viewModel) { console.log("init"); jQueryWidget(element, valueAccessor, 'dialog', function($element, options) { console.log("Creating dialog on " + $element); return $element.dialog(options); }); } }; ko.bindingHandlers.dialogcmd = { init: function(element, valueAccessor, allBindingsAccessor, viewModel) { $(element).button().click(function() { var options = ko.utils.unwrapObservable(valueAccessor()); $('#' + options.id).dialog(options.cmd || 'open'); }); } }; var viewModel = { label: ko.observable('dialog test') }; ko.applyBindings(viewModel);
ãããã¢ãããå®è£ ããã«ã¯å€ãã®æ¹æ³ããããŸãã ãã£ã¬ã¯ãã£ããŸãã¯ãã€ã³ãã£ã³ã°ãéããŠãViewModelãŸãã¯ã¢ãžã¥ãŒã«ã®äžéšãšããŠã
Angularã§ã¯ãäžèšã§èª¬æããããã«ããããã¢ããã¯$ã¹ã³ãŒãã®æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæãã$ã³ã³ãã€ã«ãµãŒãã¹ã䜿çšããŠãã³ãã¬ãŒããã³ã³ãã€ã«ããå¿ èŠããããŸãã
Knockoutã§ã¯ãæ°ããModelViewãäœæããapplyBindingsé¢æ°ãåŒã³åºããŠã¢ãã«ãšãã¥ãŒãæ¥ç¶ããå¿ èŠããããŸãããããã¢ããçšã®æ°ããããŒã¿ã¢ãã«ãäœæãããšãKnockoutããããã¢ãããã³ãã¬ãŒããã$ rootModelã«ã¢ã¯ã»ã¹ããéã«åé¡ãçºçããããšã«æ³šæããŠãã ããã Knockoutã®ããŒã¿ã¢ãã«ã®éå±€ã¯ããããDOMèŠçŽ äžã«æ§ç¯ãããŸãããããã¢ããã³ã³ãããŒãã¢ããªã±ãŒã·ã§ã³ã®ã³ã³ãããŒã®å€åŽã«ããå Žåããããã¢ããã¯$ rootModelã«ã¢ã¯ã»ã¹ã§ããŸããã
äŸ¡æ Œã®ãã©ãŒããã
AngularJSïŒ http : //jsfiddle.net/vmuha/k6ztB/1/ããã¯ã¢ãŠãïŒ http : //jsfiddle.net/vmuha/6yqDw/
æ§èœ
ããã©ãŒãã³ã¹ã®åé¡ã«ç®ãåããŸãã 2ã€ã®ãã¹ããå®è¡ãããŸããããHello WorldïŒãã¢ããªã±ãŒã·ã§ã³ã®ã³ãŒã«ãã¹ã¿ãŒããš1000èŠçŽ ã®é åã®ã¬ã³ããªã³ã°ã§ãã
ãã¹ãŠã®ãã€ã¢ã°ã©ã ã§ãåçŽæ¹å-ããªç§ãæ°Žå¹³æ¹åã«å®éšã®æ°ã

ããã§ã¯ãKnockoutã®ã³ãŒã«ãã¹ã¿ãŒããAngularã®ã³ãŒã«ãã¹ã¿ãŒããããã¯ããã«éãããšãæ確ã«ããããŸãã

ããããã¬ã³ããªã³ã°ã«é¢ããŠèšãã°ãAngularã¯æããã«ãã®åéã®ãªãŒããŒã§ãã 1000è¡ã®ã¬ã³ããªã³ã°ã§ãããããã«ãKnockoutã¯æ倧2.5ç§ããããŸãããAngularã¯ãã®ã¿ã¹ã¯ãå®äºããããã«500ããªç§æªæºã§ãã ããã«ãã¬ã³ããªã³ã°ãããèŠçŽ ããŠãŒã¶ãŒã®ç»é¢ã«è¡šç€ºããã®ã«ãããŸããŸãªæéãããããŸããAngularã§ã¯1ã3ç§ãKnockoutã§ã¯14ã20ç§ã§ãã ããã¯ãKnockoutãæååãçæããAngularãDOMèŠçŽ ãçæããããã§ãã
ãŸãšã
ç§ã«ãšã£ãŠã®äž»ãªè³ªåã¯ãAngularãšKnockoutã®ç¯å²ã決å®ããããšã§ããã ããã€ãã®ç°¡åãªå®éšã®åŸãç§ã¯æ¬¡ã®çµè«ãåºããŸããã
ããã¯ã¢ãŠãã¯ãè€éãªã¢ãŒããã¯ãã£ãè€éãªã¯ãŒã¯ãããŒãäœæããå¿ èŠããªãå Žåã«é©çšã§ããŸãã ãã®äž»ãªæ©èœã¯ãã¢ãã«ãšãã¥ãŒããªã³ã¯ããããšã§ãããããåçŽãªåäžããŒãžã®ã¢ããªã±ãŒã·ã§ã³ã«æé©ã§ãã ããšãã°ããã©ãŒã ã®è€éãã®ç°ãªãã¬ãã«ãäœæããŸãã
Angularã«é¢ããŠã¯ãRichUIã®äœæãå¿ èŠãªå Žåã«åœ¹ç«ã€ãšããçµè«ã«éããŸããã è€éãªã¢ãŒããã¯ãã£ãšè€éãªãªã³ã¯ãåããçã®å®å šãª1ããŒãžã¢ããªã±ãŒã·ã§ã³ã