คุณสามารถส่งพารามิเตอร์ไปยังตัวควบคุม AngularJS เมื่อสร้างได้หรือไม่?


278

ฉันมีตัวควบคุมที่รับผิดชอบในการสื่อสารกับ API เพื่ออัปเดตคุณสมบัติของผู้ใช้ชื่ออีเมล ฯลฯ ผู้ใช้แต่ละคนมีสิ่ง'id'ที่ส่งผ่านจากเซิร์ฟเวอร์เมื่อมีการดูหน้าโปรไฟล์

ฉันต้องการส่งค่านี้ไปยังตัวควบคุม AngularJS เพื่อให้ทราบว่าจุดเข้าใช้ API คืออะไรสำหรับผู้ใช้ปัจจุบัน ฉันพยายามส่งผ่านค่าng-controllerมา ตัวอย่างเช่น:

function UserCtrl(id, $scope, $filter) {

$scope.connection = $resource('api.com/user/' + id)

และใน HTML

<body ng-controller="UserCtrl({% id %})">

โดย{% id %}พิมพ์รหัสที่ส่งจากเซิร์ฟเวอร์ แต่ฉันได้รับข้อผิดพลาด

วิธีที่ถูกต้องในการส่งผ่านค่าเป็นตัวควบคุมในการสร้างมันคืออะไร?


6
หากคุณมี ID เป็นส่วนหนึ่งของ url คุณก็สามารถอ่าน url ได้
akonsu

ฉันมีปัญหาที่คล้ายกันมากและฉันแก้ไขมันเมื่อฉันโพสต์ในคำตอบของฉัน บางครั้งการใช้ห้องสมุดเรามองข้ามแนวคิดพื้นฐานง่ายๆของการเรียกใช้ฟังก์ชัน JavaScript
Jigar Patel

@nickponline หลังจาก 21+ คุณยังคิดว่ามันเป็นไปไม่ได้เหรอ?
om471987

คำตอบ:


362

หมายเหตุ:

คำตอบนี้เก่า นี่เป็นเพียงการพิสูจน์แนวคิดว่าผลลัพธ์ที่ต้องการสามารถบรรลุได้อย่างไร อย่างไรก็ตามอาจไม่ใช่วิธีแก้ปัญหาที่ดีที่สุดตามความเห็นด้านล่าง ฉันไม่มีเอกสารใด ๆ ที่จะสนับสนุนหรือปฏิเสธวิธีการต่อไปนี้ โปรดอ้างอิงถึงความคิดเห็นบางส่วนด้านล่างสำหรับการอภิปรายเพิ่มเติมในหัวข้อนี้

คำตอบเดิม:

ฉันตอบคำถามนี้ไปที่ใช่คุณสามารถทำได้โดยใช้ng-initและฟังก์ชั่น init อย่างง่าย

นี่คือตัวอย่างของมันในพลั่วเกอร์

HTML

<!DOCTYPE html>
<html ng-app="angularjs-starter">
  <head lang="en">
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
    <script src="app.js"></script>
  </head>  
  <body ng-controller="MainCtrl" ng-init="init('James Bond','007')">
    <h1>I am  {{name}} {{id}}</h1>
  </body>
</html>

JavaScript

var app = angular.module('angularjs-starter', []);

app.controller('MainCtrl', function($scope) {

  $scope.init = function(name, id)
  {
    //This function is sort of private constructor for controller
    $scope.id = id;
    $scope.name = name; 
    //Based on passed argument you can make a call to resource
    //and initialize more objects
    //$resource.getMeBond(007)
  };


});

5
ขอบคุณสำหรับสิ่งนี้ - ช่วยฉันลดรอยขีดข่วนได้มากและทำงานได้อย่างสมบูรณ์แบบสำหรับสถานการณ์ของฉัน ฉันต้องเริ่มต้นคอนโทรลเลอร์ด้วย object ID และนี่ก็ใช้ได้
Masonoise

26
จากเอกสาร :The only appropriate use of ngInit for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
Sergey Goliney

8
คำตอบทำให้ชัดเจนว่าคำแนะนำของ doc เทียบกับวิธีนี้ แต่ใครบางคนสามารถชี้ให้ฉันเห็นว่าเอกสารนั้นให้การแก้ปัญหาอย่างเป็นทางการหรือไม่
Michael Pell

53
ฉันคิดว่าเอกสารไม่ดีเพียงแนะนำวิธีการนี้โดยไม่ให้เหตุผลว่าทำไม ฉันคิดว่านี่เป็นวิธีที่ยอดเยี่ยม หากผู้แต่งเฟรมเวิร์กไม่ต้องการให้เฟรมเวิร์กใช้ในทางที่ผิด "พวกเขาก็ไม่ควรที่จะใช้มันในทางที่ผิด" "และให้คำแนะนำเกี่ยวกับ" วิธีการที่เหมาะสม!
Shawn de Wet

2
คำเตือน - หากคุณกำลังพยายามผูกค่าขอบเขตหรือทำสิ่งใด ๆ ที่คาดหวังว่ามูลค่านั้นจะมีอยู่ในฟังก์ชั่นคอนโทรลเลอร์มันจะใช้งานฟังก์ชั่นคอนโทรลเลอร์ก่อนแล้วng-initเกิดขึ้น - ดูplnkr.co/edit / donCm6FRBSX9oENXh9WJ? p = ดูตัวอย่าง
drzaus

143

ฉันมาสายนี้มากและฉันไม่รู้ว่านี่เป็นความคิดที่ดี แต่คุณสามารถรวม$attrsinjectable ในฟังก์ชันคอนโทรลเลอร์เพื่อให้คอนโทรลเลอร์สามารถเริ่มต้นได้โดยใช้ "อาร์กิวเมนต์" ที่มีให้ในองค์ประกอบเช่น

app.controller('modelController', function($scope, $attrs) {
    if (!$attrs.model) throw new Error("No model for modelController");

    // Initialize $scope using the value of the model attribute, e.g.,
    $scope.url = "http://example.com/fetch?model="+$attrs.model;
})

<div ng-controller="modelController" model="foobar">
  <a href="{{url}}">Click here</a>
</div>

อีกครั้งไม่คิดว่านี่เป็นความคิดที่ดี แต่ดูเหมือนว่าจะทำงานและเป็นทางเลือกอื่น


3
ฉันจะส่งผ่านวัตถุโดยใช้วิธีนี้ได้อย่างไร var obj = {a: 1, b: 2};
Neil

3
นี่เป็นวิธีแก้ปัญหาที่สมเหตุสมผลในการผลิตแอพไฮบริด
superluminary

2
@ นิล: คุณต้องแยกวัตถุ json ของคุณแล้วแยกมันภายในคอนโทรลเลอร์ ไม่ใช่โซลูชันที่ดีกว่า แต่อาจใช้งานได้ วิธีแก้ปัญหาของ Michael นั้นใช้ได้ผลดีกับพารามิเตอร์แบบสตริง ...
24790 M'sieur Toph '

1
นี่น่าเชื่อถือกว่าการใช้จริง ๆng-init- ถ้าคุณพยายามผูกค่าขอบเขตมันจะรันฟังก์ชั่นคอนโทรลเลอร์ก่อนng-initเกิดขึ้นแล้ว - ดูplnkr.co/edit/donCm6FRBSX9oENXh9WJ?p=preview
drzaus

2
ฉันไม่ได้รับ reinventing วงล้อที่มีคำสั่ง ฯลฯ หากคุณมีตัวควบคุมที่คุณต้องการใช้ในหลายมุมมองด้วยพารามิเตอร์การเริ่มต้นที่แตกต่างกันไม่กี่นี่เป็นวิธีที่ง่ายที่สุดและน่าเชื่อถือที่สุด
Eric H.

39

ยังใช้งานได้

javascript:

var app = angular.module('angularApp', []);

app.controller('MainCtrl', function($scope, name, id) {
    $scope.id = id;
    $scope.name = name;
    // and more init
});

Html:

<!DOCTYPE html>
<html ng-app="angularApp">
  <head lang="en">
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
    <script src="app.js"></script>
    <script>
       app.value("name", "James").value("id", "007");
    </script>
  </head>
  <body ng-controller="MainCtrl">
    <h1>I am  {{name}} {{id}}</h1>
  </body>
</html>

3
นี่เป็นทางออกที่ดีที่ทำงานร่วมกับกลไกการฉีดคอนสตรัคเตอร์ที่มีอยู่ คุณกำลังสร้างบริการง่าย ๆ สองอย่างที่เรียกว่า 'ชื่อ' และ 'id' หัวฉีดจะดูแลการจับคู่พวกเขาตามชื่อในระหว่างการก่อสร้าง โปรดดู: ส่วนสูตรมูลค่าของdocs.angularjs.org/guide/providers
ทอดด์

1
ดี หมายเหตุสิ่งนี้ใช้ได้กับวัตถุด้วยเช่นกันไม่ใช่แค่ชนิดดั้งเดิมเช่นสตริง
jbustamovej

ฉันชอบวิธีนี้ดีกว่า ฉันสามารถทำให้โค้ดที่ทำซ้ำของฉันเป็นโมดูลผ่านการส่งผ่านพารามิเตอร์ ไชโย!
agentpx

นี่เป็นวิธีที่
งี่เง่า

สิ่งนี้เป็นการตั้งค่าคู่คีย์ / ค่าโกลบอลหรือไม่? สิ่งเหล่านี้สามารถถูกกำหนดขอบเขตให้กับอินสแตนซ์ของตัวควบคุมที่กำหนดเพื่อที่จะได้รับเฉพาะบนตัวควบคุมลูกภายใต้ตัวควบคุมหลักเท่านั้น ถ้าไม่ใช่ดูเหมือนว่านี่จะไม่แตกต่างจากการตั้งค่าตัวแปร Javascript ทั่วโลกปกติที่ระดับหน้าต่าง
jpierson

16

มุมมองไม่ควรกำหนดค่า

ในเชิงมุมเทมเพลตไม่ควรทำการกำหนดค่าซึ่งเป็นสิ่งที่คนต้องการเมื่อพวกเขาต้องการส่งอาร์กิวเมนต์ไปยังตัวควบคุมจากไฟล์เทมเพลต นี่จะกลายเป็นความชันที่ลื่น หากการตั้งค่าการกำหนดค่านั้นถูกกำหนดค่าตายตัวในเทมเพลต (เช่นโดยแอตทริบิวต์คำสั่งหรือตัวควบคุมอาร์กิวเมนต์) คุณจะไม่สามารถใช้เทมเพลตนั้นซ้ำได้อีกต่อไปยกเว้นการใช้ครั้งเดียว ในไม่ช้าคุณจะต้องการใช้เทมเพลตนั้นอีกครั้ง แต่ด้วยการตั้งค่าที่แตกต่างกันและในตอนนี้เพื่อที่จะทำเช่นนั้นคุณจะทำการประมวลผลแม่แบบล่วงหน้าเพื่อฉีดตัวแปรก่อนที่มันจะถูกส่งไปยังเชิงมุมหรือใช้คำสั่งขนาดใหญ่ บล็อกของ HTML เพื่อให้คุณใช้ HTML ควบคุมทั้งหมดอีกครั้งยกเว้น div wrapper และอาร์กิวเมนต์ สำหรับโครงการขนาดเล็กมันไม่ใช่เรื่องใหญ่ สำหรับสิ่งที่ยิ่งใหญ่ (สิ่งที่เชิงมุมเก่ง) มันน่าเกลียดอย่างรวดเร็ว

ทางเลือก: โมดูล

การกำหนดค่าประเภทนี้เป็นโมดูลที่ออกแบบมาเพื่อจัดการ ในแบบฝึกหัดเชิงมุมหลายคนมีโมดูลเดียวสำหรับแอปพลิเคชันทั้งหมดของพวกเขา แต่จริงๆแล้วระบบได้รับการออกแบบและรองรับโมดูลขนาดเล็กจำนวนมากโดยแต่ละอันครอบคลุมส่วนเล็ก ๆ ของแอปพลิเคชันทั้งหมด ตามหลักแล้วตัวควบคุมโมดูลและอื่น ๆ จะถูกประกาศในไฟล์แยกกันและต่อเข้าด้วยกันในชิ้นส่วนที่ใช้งานได้อีกครั้ง เมื่อแอปพลิเคชันของคุณได้รับการออกแบบด้วยวิธีนี้คุณจะได้รับประโยชน์มากมายจากข้อโต้แย้งที่ใช้งานง่าย

ตัวอย่างด้านล่างมี 2 โมดูลซึ่งใช้คอนโทรลเลอร์เดียวกันซ้ำอีกครั้ง แต่แต่ละโมดูลจะมีการตั้งค่าของตนเอง module.valueการตั้งค่าการกำหนดค่าที่ส่งผ่านฉีดพึ่งพาการใช้ สิ่งนี้เป็นไปตามวิธีเชิงมุมเพราะเรามีสิ่งต่อไปนี้: การฉีดขึ้นอยู่กับคอนสตรัคเตอร์รหัสคอนโทรลเลอร์ที่ใช้ซ้ำได้เทมเพลตควบคุมที่สามารถใช้ซ้ำได้ (ตัวควบคุม div สามารถรวมกับ ng-include ได้อย่างง่ายดาย) โมดูลเป็นยานพาหนะสำหรับเย็บชิ้นด้วยกัน

นี่คือตัวอย่าง:

<!-- index.html -->
<div id="module1">
    <div ng-controller="MyCtrl">
        <div>{{foo}}</div>
    </div>
</div>
<div id="module2">
    <div ng-controller="MyCtrl">
        <div>{{foo}}</div>
    </div>
</div>
<script>
    // part of this template, or a JS file designed to be used with this template
    angular.element(document).ready(function() {
        angular.bootstrap(document.getElementById("module1"), ["module1"]);
        angular.bootstrap(document.getElementById("module2"), ["module2"]);
    });
</script>

<!-- scripts which will likely in be in their seperate files -->
<script>
    // MyCtrl.js
    var MyCtrl = function($scope, foo) {
    $scope.foo = foo;
    }

    MyCtrl.$inject = ["$scope", "foo"];

    // Module1.js
    var module1 = angular.module('module1', []);
    module1.value("foo", "fooValue1");
    module1.controller("MyCtrl", MyCtrl);

    // Module2.js file
    var module2 = angular.module('module2', []);
    module2.value("foo", "fooValue2");
    module2.controller("MyCtrl", MyCtrl);
</script>

เห็นมันในการกระทำ: jsFiddle


ฉันลงทะเบียนแล้ว แต่ฉันต้องการที่จะขอบคุณสำหรับการสนับสนุนของคุณ คำตอบนี้ทำให้ฉันอยู่ในเส้นทางที่ดีกว่า stackoverflow ดีที่สุดเมื่อผู้คนแบ่งปันแนวทางปฏิบัติที่ดีที่สุดและไม่ใช่เพียงแค่ข้อมูลโค้ดที่แฮ็ก สิ่งนี้ยอดเยี่ยม: "เทมเพลตไม่ควรกำหนดค่าซึ่งโดยเนื้อแท้แล้วสิ่งที่ผู้คนปรารถนาเมื่อพวกเขาต้องการส่งอาร์กิวเมนต์ไปยังตัวควบคุมจากไฟล์เทมเพลต" ขอบคุณที่มีการมองเห็นเลเซอร์ในหัวใจของเรื่อง
pestophagous

15

เช่นเดียวกับ @akonsu และไนเจล Findlater ขอแนะนำให้คุณสามารถอ่าน URL URL ที่เป็นindex.html#/user/:idกับ$routeParams.idและใช้การควบคุมภายใน

แอปของคุณ:

var app = angular.module('myApp', [ 'ngResource' ]);

app.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/:type/:id', {templateUrl: 'myView.html', controller: 'myCtrl'});
}]);

บริการทรัพยากร

app.factory('MyElements', ['$resource', function($resource) {
     return $resource('url/to/json/:type/:id', { type:'@type', id:'@id' });
}]);

ตัวควบคุม

app.controller('MyCtrl', ['$scope', '$routeParams', 'MyElements', function($scope, $routeParams, MyElements) {
    MyElements.get({'type': $routeParams.type, "id": $routeParams.id }, function(elm) {
        $scope.elm = elm;
    })
}]);

แล้วจะสามารถเข้าถึงได้ในมุมมองขึ้นอยู่กับelmid


8

หากng-initไม่ใช่เพื่อส่งวัตถุเข้า$scopeคุณสามารถเขียนคำสั่งของคุณเองได้เสมอ ดังนั้นนี่คือสิ่งที่ฉันได้รับ:

http://jsfiddle.net/goliney/89bLj/

JavaSript:

var app = angular.module('myApp', []);
app.directive('initData', function($parse) {
    return function(scope, element, attrs) {
        //modify scope
        var model = $parse(attrs.initData);
        model(scope);
    };
});

function Ctrl1($scope) {
    //should be defined
    $scope.inputdata = {foo:"east", bar:"west"};
}

Html:

<div ng-controller="Ctrl1">
    <div init-data="inputdata.foo=123; inputdata.bar=321"></div>
</div>

แต่วิธีการของฉันสามารถแก้ไขวัตถุซึ่งกำหนดไว้แล้วที่คอนโทรลเลอร์


สำหรับการอ้างอิงนี้ใช้งานได้ดี แต่ในเวอร์ชันเชิงมุมของปัจจุบันคือ $ attrs (vs attrs)
Dinis Cruz

8

ดูเหมือนว่าทางออกที่ดีที่สุดสำหรับคุณคือคำสั่ง สิ่งนี้ช่วยให้คุณยังคงมีคอนโทรลเลอร์ของคุณ แต่กำหนดคุณสมบัติที่กำหนดเองสำหรับมัน

ใช้สิ่งนี้หากคุณต้องการเข้าถึงตัวแปรในขอบเขตการตัด:

angular.module('myModule').directive('user', function ($filter) {
  return {
    link: function (scope, element, attrs) {
      $scope.connection = $resource('api.com/user/' + attrs.userId);
    }
  };
});

<user user-id="{% id %}"></user>

ใช้สิ่งนี้หากคุณไม่ต้องการเข้าถึงตัวแปรในขอบเขตการล้อม:

angular.module('myModule').directive('user', function ($filter) {
  return {
    scope: {
      userId: '@'
    },
    link: function (scope, element, attrs) {
      $scope.connection = $resource('api.com/user/' + scope.userId);
    }
  };
});

<user user-id="{% id %}"></user>

7

ฉันพบตัวแปรส่งผ่านจาก $ routeProvider มีประโยชน์

ตัวอย่างเช่นคุณใช้คอนโทรลเลอร์หนึ่ง MyController สำหรับหลายหน้าจอผ่านตัวแปร "mySuperConstant" ที่สำคัญบางอย่างภายใน

ใช้โครงสร้างอย่างง่ายที่:

Router:

$routeProvider
            .when('/this-page', {
                templateUrl: 'common.html',
                controller: MyController,
                mySuperConstant: "123"
            })
            .when('/that-page', {
                templateUrl: 'common.html',
                controller: MyController,
                mySuperConstant: "456"
            })
            .when('/another-page', {
                templateUrl: 'common.html',
                controller: MyController,
                mySuperConstant: "789"
            })

MyController:

    MyController: function ($scope, $route) {
        var mySuperConstant: $route.current.mySuperConstant;
        alert(mySuperConstant);

    }

6

คุณสามารถทำได้เมื่อตั้งค่าเส้นทางสำหรับเช่น

 .when('/newitem/:itemType', {
            templateUrl: 'scripts/components/items/newEditItem.html',
            controller: 'NewEditItemController as vm',
            resolve: {
              isEditMode: function () {
                return true;
              }
            },
        })

และต่อมาใช้เป็น

(function () {
  'use strict';

  angular
    .module('myApp')
    .controller('NewEditItemController', NewEditItemController);

  NewEditItemController.$inject = ['$http','isEditMode',$routeParams,];

  function NewEditItemController($http, isEditMode, $routeParams) {
    /* jshint validthis:true */

    var vm = this;
    vm.isEditMode = isEditMode;
    vm.itemType = $routeParams.itemType;
  }
})();

ดังนั้นที่นี่เมื่อเราตั้งค่าเส้นทางที่เราส่ง: itemType และเรียกคืนในภายหลังจาก $ routeParams


4

มีวิธีอื่นในการส่งผ่านพารามิเตอร์ไปยังตัวควบคุมโดยการฉีด $ routeParams เข้าไปในคอนโทรลเลอร์ของคุณแล้วใช้พารามิเตอร์ url ที่อธิบายไว้ที่นี่วิธีรัดกุมที่สุดในการอ่านพารามิเตอร์การค้นหาใน AngularJS คืออะไร


3

คำถามนี้เก่า แต่ฉันพยายามเป็นเวลานานในการพยายามหาคำตอบสำหรับปัญหานี้ที่จะใช้งานได้ตามความต้องการของฉันและไม่สามารถหาได้ง่าย ฉันเชื่อว่าวิธีแก้ไขปัญหาต่อไปนี้ดีกว่าโซลูชันที่ยอมรับในปัจจุบันบางทีอาจเป็นเพราะเชิงมุมได้เพิ่มฟังก์ชันการทำงานเนื่องจากคำถามนี้ถูกวางเดิม

คำตอบสั้น ๆ โดยใช้วิธีการ Module.value ช่วยให้คุณสามารถส่งผ่านข้อมูลไปยังตัวสร้างคอนโทรลเลอร์

ดูพลั่วของฉันที่นี่

ฉันสร้างโมเดลวัตถุจากนั้นเชื่อมโยงกับคอนโทรลเลอร์ของโมดูลโดยอ้างอิงกับชื่อ 'model'

HTML / JS

  <html>
  <head>
    <script>
      var model = {"id": 1, "name":"foo"};

      $(document).ready(function(){
        var module = angular.module('myApp', []);
        module.value('model', model);
        module.controller('MyController', ['model', MyController]);
        angular.bootstrap(document, ['myApp']);
      });

      function confirmModelEdited() {
        alert("model name: " + model.name + "\nmodel id: " + model.id);
      }
    </script>

  </head>
  <body >
      <div ng-controller="MyController as controller">
        id: {{controller.model.id}} <br>
        name: <input ng-model="controller.model.name"/>{{controller.model.name}}
        <br><button ng-click="controller.incrementId()">increment ID</button>
        <br><button onclick="confirmModelEdited()">confirm model was edited</button>
    </div>
  </body>

</html>

คอนสตรัคในตัวควบคุมของฉันนั้นยอมรับพารามิเตอร์ที่มี 'ตัวจำลอง' ตัวระบุเดียวกันซึ่งมันสามารถเข้าถึงได้

ตัวควบคุม

function MyController (model) {
  this.model = model;
}

MyController.prototype.incrementId = function() {
  this.model.id = this.model.id + 1;
}

หมายเหตุ:

ฉันใช้การกำหนดค่าเริ่มต้นด้วยตนเองของการบูตสแตรปปิ้งซึ่งทำให้ฉันสามารถเริ่มต้นแบบของฉันก่อนส่งไปยังเชิงมุม สิ่งนี้เล่นได้ดีกว่าด้วยรหัสที่มีอยู่ในขณะที่คุณสามารถรอการตั้งค่าข้อมูลที่เกี่ยวข้องของคุณและรวบรวมเฉพาะชุดย่อยเชิงมุมของแอปของคุณตามต้องการเมื่อคุณต้องการ

ในพลั่วเกอร์ฉันได้เพิ่มปุ่มเพื่อแจ้งเตือนค่าของวัตถุต้นแบบที่กำหนดไว้ในจาวาสคริปต์และส่งผ่านไปยังเชิงมุมเพียงเพื่อยืนยันว่าเชิงมุมหมายถึงการอ้างอิงวัตถุจำลองอย่างแท้จริงแทนที่จะคัดลอกและทำงานกับสำเนา

ในบรรทัดนี้:

module.controller('MyController', ['model', MyController]);

ฉันส่งวัตถุ MyController ไปยังฟังก์ชัน Module.controller แทนที่จะประกาศว่าเป็นฟังก์ชันอินไลน์ ฉันคิดว่านี่ช่วยให้เรากำหนดวัตถุคอนโทรลเลอร์ได้ชัดเจนยิ่งขึ้น แต่เอกสารเชิงมุมมีแนวโน้มที่จะทำแบบอินไลน์ดังนั้นฉันคิดว่ามันชัดเจน

ฉันใช้ไวยากรณ์ "controller as" และกำหนดค่าให้กับคุณสมบัติ "this" ของ MyController แทนที่จะใช้ตัวแปร "$ scope" ฉันเชื่อว่าสิ่งนี้จะทำงานได้ดีโดยใช้ $ scope เช่นกันการกำหนดคอนโทรลเลอร์จะมีลักษณะดังนี้:

module.controller('MyController', ['$scope', 'model', MyController]);

และตัวสร้างคอนโทรลเลอร์จะมีลายเซ็นดังนี้:

function MyController ($scope, model) {

หากคุณต้องการด้วยเหตุผลใดก็ตามคุณสามารถแนบโมเดลนี้เป็นค่าของโมดูลที่สองซึ่งคุณต้องแนบเป็นการอ้างอิงกับโมดูลหลักของคุณ

ฉันเชื่อว่าวิธีแก้ปัญหาของเขาดีกว่าที่ยอมรับในปัจจุบันมากเพราะ

  1. รูปแบบที่ส่งผ่านไปยังคอนโทรลเลอร์เป็นวัตถุจาวาสคริปต์ไม่ใช่สตริงที่ได้รับการประเมิน มันคือการอ้างอิงที่แท้จริงไปยังวัตถุและการเปลี่ยนแปลงที่มีผลต่อการอ้างอิงอื่น ๆ ไปยังวัตถุรูปแบบนี้
  2. Angular กล่าวว่าการใช้คำตอบที่ยอมรับของ ng-init นั้นเป็นการใช้ในทางที่ผิดซึ่งโซลูชันนี้ไม่ได้ทำ

วิธีที่แองกูลาร์ดูเหมือนจะทำงานในตัวอย่างอื่น ๆ ส่วนใหญ่ทั้งหมดที่ฉันเคยเห็นมีคอนโทรลเลอร์กำหนดข้อมูลของโมเดลซึ่งไม่สมเหตุสมผลสำหรับฉันไม่มีการแยกระหว่างโมเดลและคอนโทรลเลอร์ที่ดูเหมือนจะไม่จริง MVC กับฉัน วิธีการแก้ปัญหานี้ช่วยให้คุณมีรูปแบบวัตถุแยกต่างหากที่คุณส่งผ่านเข้าไปในคอนโทรลเลอร์ นอกจากนี้ถ้าคุณใช้คำสั่ง ng-include คุณสามารถใส่ html เชิงมุมทั้งหมดของคุณลงในไฟล์แยกกันแยกมุมมองแบบจำลองและตัวควบคุมออกเป็นชิ้นส่วนแยกต่างหาก


2

หากใช้ angular-ui-router นี่เป็นวิธีแก้ไขที่ถูกต้อง: https://github.com/angular-ui/ui-router/wiki#resolve

โดยทั่วไปคุณประกาศชุดของการพึ่งพาเพื่อ "แก้ไข" ก่อนที่ตัวควบคุมจะถูกสร้างอินสแตนซ์ คุณอาจประกาศการขึ้นต่อกันสำหรับ "สถานะ" แต่ละรายการ การอ้างอิงเหล่านี้จะถูกส่งผ่านใน "ตัวสร้าง" ของตัวควบคุม


1

วิธีหนึ่งในการทำเช่นนั้นคือการมีบริการแยกต่างหากที่สามารถใช้เป็น 'เรือ' สำหรับข้อโต้แย้งเหล่านั้นที่พวกเขาเป็นสมาชิกข้อมูลสาธารณะ


คำตอบที่ดีที่สุด IMO ขณะนี้ฉันยังใช้ที่เก็บข้อมูลเบราว์เซอร์ในบางกรณีสำหรับผู้ใช้ที่กล้าที่จะกด F5 ดังนั้นสถานะนี้จึงได้รับการปรับปรุง
Dormouse

1

ฉันไม่ชอบวิธีแก้ไขปัญหาใด ๆ ที่นี่สำหรับกรณีการใช้งานเฉพาะของฉันดังนั้นฉันจึงคิดว่าฉันโพสต์สิ่งที่ทำเพราะฉันไม่เห็นมันที่นี่

ฉันแค่อยากจะใช้คอนโทรลเลอร์มากกว่าคำสั่งภายในลูปซ้ำ - ng:

<div ng-repeat="objParameter in [{id:'a'},{id:'b'},{id:'c'}]">
  <div ng-controller="DirectiveLikeController as ctrl"></div>
</div>

ตอนนี้เพื่อเข้าถึงการobjParameterสร้างบนภายในแต่ละ DirectiveLikeController (หรือรับ objParameter ที่ทันสมัยในเวลาใดก็ได้) ทั้งหมดที่ฉันต้องทำคือการฉีดขอบเขต $ และโทร$scope.$eval('objParameter'):

var app = angular.module('myapp', []);
app.controller('DirectiveLikeController',['$scope'], function($scope) {
   //print 'a' for the 1st instance, 'b' for the 2nd instance, and 'c' for the 3rd.
   console.log($scope.$eval('objParameter').id); 
});

objParameterข้อเสียเดียวจริงที่ผมเห็นก็คือว่ามันต้องมีการควบคุมผู้ปกครองที่จะรู้ว่าพารามิเตอร์การตั้งชื่อ


0

ไม่เป็นไปไม่ได้ ฉันคิดว่าคุณสามารถใช้ NG-init เป็นสับhttp://docs.angularjs.org/api/ng.directive:ngInit


4
ฉันขอแตกต่างกัน แต่คุณสามารถทำได้โดยใช้ ng-init และใช้ fuction init
Jigar Patel

คำเตือน - หากคุณกำลังพยายามผูกค่าขอบเขตหรือทำสิ่งใด ๆ ที่คาดหวังว่ามูลค่านั้นจะมีอยู่ในฟังก์ชั่นคอนโทรลเลอร์มันจะใช้งานฟังก์ชั่นคอนโทรลเลอร์ก่อนแล้วng-initเกิดขึ้น - ดูplnkr.co/edit / donCm6FRBSX9oENXh9WJ? p = ดูตัวอย่าง
drzaus

ใช่มันเป็นไปได้ อย่างน้อยที่สุดคุณจะใช้ data-params หรืออะไรก็ตาม แต่มันเป็นไปได้แน่นอน
Juan

0

นี่คือวิธีการแก้ปัญหา (ตามคำแนะนำของ Marcin Wyszynski) ซึ่งทำงานที่คุณต้องการส่งค่าไปยังคอนโทรลเลอร์ของคุณ แต่คุณไม่ได้ประกาศตัวควบคุมใน html ของคุณ (ตัวอย่างเช่น ng-init ต้องการ) - ตัวอย่างเช่น คุณกำลังแสดงเทมเพลตของคุณด้วย ng-view และประกาศคอนโทรลเลอร์แต่ละตัวสำหรับเส้นทางที่เกี่ยวข้องผ่าน routeProvider

JS

messageboard.directive('currentuser', ['CurrentUser', function(CurrentUser) {
  return function(scope, element, attrs) {
    CurrentUser.name = attrs.name;
  };
}]);

HTML

<div ng-app="app">
  <div class="view-container">
    <div ng-view currentuser name="testusername" class="view-frame animate-view"></div>
  </div>
</div>

ในการแก้ปัญหานี้ CurrentUser เป็นบริการที่สามารถฉีดเข้าไปในตัวควบคุมใด ๆ ที่มีคุณสมบัติ. name แล้วพร้อมใช้งาน

หมายเหตุสองประการ:

  • ปัญหาที่ฉันพบคือ. name จะถูกตั้งค่าหลังจากที่ตัวควบคุมโหลดขึ้นมาดังนั้นเพื่อแก้ไขปัญหาฉันมีเวลาสั้น ๆ ก่อนที่จะแสดงชื่อผู้ใช้ในขอบเขตของตัวควบคุม มีวิธีที่เรียบร้อยในการรอจนกระทั่ง. name ตั้งอยู่บนบริการหรือไม่

  • สิ่งนี้ให้ความรู้สึกว่าเป็นวิธีที่ง่ายมากในการนำผู้ใช้ปัจจุบันไปยังแอพพลิเคชั่น Angular ของคุณพร้อมกับการตรวจสอบสิทธิ์ทั้งหมดที่อยู่นอกแองกูลา คุณสามารถมี before_filter เพื่อป้องกันผู้ใช้ที่ไม่ได้เข้าสู่ระบบไปที่ html ซึ่งแอป Angular ของคุณถูก bootstrapped ในและภายใน html นั้นคุณสามารถสอดแทรกชื่อผู้ใช้ที่เข้าสู่ระบบและแม้แต่ ID ของพวกเขาหากคุณต้องการโต้ตอบกับรายละเอียดของผู้ใช้ ผ่านคำขอ http จากแอปเชิงมุมของคุณ คุณสามารถอนุญาตให้ผู้ใช้ที่ไม่ได้ลงชื่อเข้าใช้สามารถใช้แอพพลิเคชั่น Angular กับ 'ผู้ใช้ทั่วไป' ที่เป็นค่าเริ่มต้น คำแนะนำใด ๆ เกี่ยวกับสาเหตุที่วิธีการนี้ไม่ดีจะได้รับการต้อนรับ - รู้สึกง่ายเกินไปที่จะมีเหตุผล!)


0

นี่คือการขยายตัวของ @Michael ไถนาของคำตอบที่ดี คำตอบของเขาทำงานเพื่อเริ่มต้นตัวแปรจากมุมมองโดยการฉีด$attrsวัตถุเข้าไปในตัวควบคุม ปัญหาเกิดขึ้นหากมีการเรียกตัวควบคุมเดียวกันจาก$routeProviderเมื่อคุณนำทางโดยการกำหนดเส้นทาง จากนั้นคุณจะได้รับข้อผิดพลาดของหัวฉีดUnknown provider : $attrsProviderเนื่องจาก$attrsจะสามารถใช้งานได้เฉพาะเมื่อมีการรวบรวมมุมมอง การแก้ปัญหาคือการส่งผ่านตัวแปร (foo) ผ่าน$routeParamsเมื่อเริ่มต้นตัวควบคุมจากเส้นทางและ$attrsเมื่อเริ่มต้นตัวควบคุมจากมุมมอง นี่คือทางออกของฉัน

จากเส้นทาง

$routeProvider.
        when('/mypage/:foo', {
            templateUrl: 'templates/mypage.html',
            controller: 'MyPageController',
            caseInsensitiveMatch: true,
            resolve: {
                $attrs: function () {
                    return {};
                }
            }
        });

นี้จับ URL '/mypage/bar'เช่น อย่างที่คุณเห็นว่า foo ถูกส่งผ่านโดย url param และเราให้$injectorวัตถุว่างเปล่าเพื่อ$attrsให้ไม่มีข้อผิดพลาดของหัวฉีด

จากมุมมอง

<div ng-controller="MyPageController" data-foo="bar">

</div>

ตอนนี้ตัวควบคุม

var app = angular.module('myapp', []);
app.controller('MyPageController',['$scope', '$attrs', '$routeParams'], function($scope, $attrs, $routeParams) {
   //now you can initialize foo. If $attrs contains foo, it's been initialized from view
   //else find it from $routeParams
   var foo = $attrs.foo? $attrs.foo : $routeParams.foo;
   console.log(foo); //prints 'bar'

});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.