ตำแหน่ง AngularJS $ ไม่เปลี่ยนเส้นทาง


126

ฉันมีปัญหาในการเปลี่ยน URL ของหน้าหลังจากส่งแบบฟอร์มแล้ว

นี่คือขั้นตอนของแอปของฉัน:

  1. กำหนดเส้นทางแล้ว URL จะถูกจดจำในหน้าฟอร์มบางหน้า
  2. การโหลดหน้าตัวควบคุมชุดตัวแปรคำสั่งจะเริ่มทำงาน
  3. คำสั่งรูปแบบพิเศษจะเริ่มทำงานซึ่งดำเนินการส่งแบบฟอร์มพิเศษโดยใช้ AJAX
  4. หลังจากดำเนินการ AJAX แล้ว (Angular ไม่ดูแล AJAX) การเรียกกลับจะเริ่มทำงานและคำสั่งจะเรียกใช้$scope.onAfterSubmitฟังก์ชันที่กำหนดตำแหน่ง

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

ฉันได้ทดสอบเพื่อดูว่าโค้ดไปถึงonAfterSubmitฟังก์ชัน (ซึ่งทำ)

ความคิดเดียวของฉันคือขอบเขตของฟังก์ชั่นเปลี่ยนไปอย่างใด (เนื่องจากถูกเรียกจากคำสั่ง) แต่จะเรียกอีกครั้งได้อย่างไรว่าonAfterSubmitขอบเขตเปลี่ยนไป?

นี่คือรหัสของฉัน

var Ctrl = function($scope, $location, $http) {
  $http.get('/resources/' + $params.id + '/edit.json').success(function(data) {
    $scope.resource = data;
  });

  $scope.onAfterSubmit = function() {
    $location.path('/').replace();
  };
}
Ctrl.$inject = ['$scope','$location','$http'];

ใครช่วยฉันหน่อยได้ไหม


1
อาจซ้ำกันได้ของAngular $ location.path ไม่ทำงาน
Jim G.

โปรดทราบว่าสิ่งนี้ถูกสร้างขึ้นหนึ่งปีก่อนหน้านั้น
matsko

ถูกต้องและมีสิทธิประโยชน์อีกหนึ่งปีอีกคนหนึ่งมีคำตอบที่ได้รับการยอมรับที่ถูกต้องมากขึ้น
Jim G.

1
@JimG นี่ไม่ใช่คำถามที่ซ้ำกันคำถามนี้เมื่อ 4 ปีที่แล้วคำถามที่คุณลิงก์คือเมื่อ 2 ปีที่แล้ว
Castro Roy

คำตอบ:


298

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

$ apply () ใช้เพื่อดำเนินการนิพจน์ในเชิงมุมจากภายนอกกรอบเชิงมุม (ตัวอย่างเช่นจากเหตุการณ์ DOM ของเบราว์เซอร์ setTimeout, XHR หรือไลบรารีของบุคคลที่สาม)

ลองใช้$scope.$apply()ทันทีหลังจากที่คุณเปลี่ยนสถานที่และโทรreplace()แจ้งให้ Angular รู้ว่ามีการเปลี่ยนแปลง


1
ใช้งานได้เหมือนมีเสน่ห์ ฉันได้เพิ่มรหัสที่ฉันใช้ในโพสต์ของคุณเพื่อให้มันใช้งานได้ :) ขอบคุณมาก !!!
matsko

4
เพื่อให้ได้แนวคิดที่ดีขึ้นว่า $ ใช้ทำงานร่วมกับเชิงมุมอย่างไรและวิธีการแก้ไขปัญหาต่อไปนี้เป็นลิงค์สำหรับyearofmoo.com/2012/10/…
matsko

2
@Skeater คุณสามารถฉีดขอบเขตรูทและดำเนินการได้ดังนี้ factory ('xyz', ['$ rootScope', function ($ rootScope) {... }])
F Lekschas

4
สามารถตัดการโทรกลับของคุณด้วย $ timeout และขอบเขตจะถูกนำไปใช้อย่างถูกต้อง
JasonS

7
เหมือนที่ JasonS บอกใช้ $ timeout (function () {// ใช้การเปลี่ยนแปลงที่นี่}); สิ่งนี้มีข้อดีสองประการ: 1) คุณไม่จำเป็นต้องเข้าถึง $ ขอบเขต 2) คุณไม่ต้องกังวลเกี่ยวกับ $ ใช้ alredy ทำงาน ด้วยเหตุผลประการที่ 2 การใช้ $ timeout มักเป็นแนวทางที่ต้องการ
ArneHugo

56

แทนการเปลี่ยนแปลงหรือรีเฟรชหน้าผมใช้บริการ$location.path(...) $windowใน Angular บริการนี้ใช้เป็นส่วนต่อประสานกับwindowออบเจ็กต์และwindowอ็อบเจ็กต์มีคุณสมบัติlocationที่ช่วยให้คุณสามารถจัดการการดำเนินการที่เกี่ยวข้องกับตำแหน่งหรือเนื้อหา URL

ตัวอย่างเช่นwindow.locationคุณสามารถกำหนดหน้าใหม่ได้ดังนี้:

$window.location.assign('/');

หรือรีเฟรชเช่นนี้:

$window.location.reload();

มันได้ผลสำหรับฉัน แตกต่างจากที่คุณคาดหวังเล็กน้อย แต่ใช้ได้ผลตามเป้าหมายที่กำหนด


3
ฉันเช่นกัน $ location.path () ไม่เปลี่ยนเส้นทางเมื่อ url มี params
Sudhakar

2
นี่คือคำตอบที่ถูกต้อง ดูที่นี่
เออร์วิง

28

ฉันมีปัญหาเดียวกันนี้ แต่การโทรไปยัง $ location นั้นอยู่ในอีเมลสรุปแล้ว การโทรไปที่ $ apply () ทำให้ $ Digest เกิดข้อผิดพลาดในกระบวนการ

เคล็ดลับนี้ใช้ได้ผล (และอย่าลืมฉีด$locationเข้าไปในคอนโทรลเลอร์ของคุณ):

$timeout(function(){ 
   $location...
},1);

แม้ว่าจะไม่รู้ว่าทำไมถึงจำเป็น ...


5
นี่เป็นความคิดที่ไม่ดี เพียงตรวจสอบเฟสในกรณีที่อยู่ในการสรุปข้อมูลจากนั้นคุณสามารถข้ามการใช้งานได้ Angular จะตามทันและเปลี่ยน URL ของมันเอง: coderwall.com/p/ngisma
matsko

3
การหมดเวลาดูเหมือนเป็นการแฮ็คที่สกปรกสำหรับฉัน หาก href ของคุณมี "#" แสดงว่า $ location.path () ไม่ทำงานตามที่คาดไว้ เพียงลบ href = "#" ทั้งหมดบนแท็กของคุณหรือเพียงแค่ตั้งค่าเป็น href = "" และคุณไม่จำเป็นต้องใช้ $ timeout
Shankar ARUL - jupyterdata.com

7
$$ phase เป็นตัวแปรส่วนตัวที่คุณไม่ควรพยายามเข้าถึงเนื่องจากอาจมีการเปลี่ยนแปลงใน angularjs เวอร์ชันใหม่
Blaise

7
การใช้ $ timeout อาจเป็นการแฮ็ก แต่การใช้ $$ phase เป็นการแฮ็กที่ยิ่งใหญ่กว่า โดยทั่วไปห้ามดูหรือแตะสิ่งที่ขึ้นต้นด้วย $$
nilskp

3
หลังจากผ่านไปประมาณ 10 ชั่วโมงของการสุ่มทำลาย ... วิธีนี้ใช้ได้ผลสำหรับฉัน!
Shakeel

6

ฉันต้องฝัง$location.path()คำสั่งของฉันแบบนี้เพราะไดเจสต์ของฉันยังทำงานอยู่:

       function routeMe(data) {                
            var waitForRender = function () {
                if ($http.pendingRequests.length > 0) {
                    $timeout(waitForRender);
                } else {
                    $location.path(data);
                }
            };
            $timeout(waitForRender);
        }

1
ขอบคุณสำหรับฟังก์ชั่นมีประโยชน์มาก!
Bill Effin Murray

สำหรับฉันปัญหาคือเราใช้ angular-block-ui และมันขัดขวางการอัปเดตตำแหน่งแถบที่อยู่ เราตกแต่งคำขอ $ http ด้วยบูลที่ requestFilter ของเราหยิบขึ้นมาเพื่อไม่ให้ block-ui เรียกใช้การโทรนั้นจากนั้นทุกอย่างก็เรียบร้อยดี
matao

2

ในกรณีของฉันปัญหาคือตัวบ่งชี้พารามิเตอร์ทางเลือก ('?') หายไปในการกำหนดค่าเทมเพลตของฉัน

ตัวอย่างเช่น:

.when('/abc/:id?', {
    templateUrl: 'views/abc.html',
    controller: 'abcControl'
})


$location.path('/abc');

หากไม่มีอักขระสอบสวนเส้นทางจะไม่เปลี่ยนการระงับพารามิเตอร์เส้นทางอย่างชัดเจน


ไม่ใช่การกำหนดค่าเทมเพลตแต่เป็นการกำหนดค่าเส้นทาง
Piotr Dobrogost

1

หากมีใครใช้ Angular-ui / ui-router ให้ใช้: $state.go('yourstate')แทนการใช้$location. มันเป็นเคล็ดลับสำหรับฉัน



0

ในความคิดของฉันคำตอบหลายคำที่นี่ดูเหมือนจะแฮ็คเล็กน้อย (เช่น $ apply () หรือ $ timeout) เนื่องจากการยุ่งกับ $ apply () อาจทำให้เกิดข้อผิดพลาดที่ไม่ต้องการได้

โดยปกติแล้วเมื่อ $ location ไม่ทำงานหมายความว่ามีบางอย่างไม่ได้ใช้งานในลักษณะเชิงมุม

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

รหัสเก่า:

taskService.createTask(data).then(function(code){
            $location.path("task/" + code);
        }, function(error){});

หมายเหตุ: taskService.createTask ส่งคืนสัญญา

$ q - วิธีเชิงมุมในการใช้คำสัญญา:

let dataPromises = [taskService.createTask(data)];
        $q.all(dataPromises).then(function(response) {
                let code = response[0];
                $location.path("task/" + code);
            }, 
            function(error){});

การใช้ $ q เพื่อแก้ไขคำมั่นสัญญาช่วยแก้ปัญหาการเปลี่ยนเส้นทาง

เพิ่มเติมเกี่ยวกับบริการ $ q: https://docs.angularjs.org/api/ng/service/ $ q


-8
setTimeout(function() { $location.path("/abc"); },0);

ควรแก้ปัญหาของคุณ


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