Steps to properly create your own angular service with XHR

Exploring the world of AngularJS, I embarked on a mission to create a file upload feature along with other form data. While there are numerous scripts and plugins available, I decided to utilize my own custom service using $xhr. Despite successfully sending the file, I encountered an error, bug (not an actual error or bug, just used as placeholders) which made me question my understanding of AngularJS. Here's a snippet of my code:
.
JS

var app = angular.module('ngnNews', []);
app.factory('posts', [function () {...}]); // Trimmed for brevity

app.factory('$xhr', function () {
    var $xhr = { reqit: function (components) { ... //My Xml HTTP Request codes here }}
    return $xhr;
});

app.controller('MainCtrl', ['$http','$scope','$xhr','posts',
    function ($http, $scope, $xhr, posts) {
        $scope.posts = posts.posts;

        $scope.files = [];
        var newPost = { title: 'post one', upvotes: 20, downvotes: 5 };
        $scope.posts.push(newPost);

        $scope.addPost = function () {
            $xhr.reqit({
                form: document.getElementById('postForm'),
                callbacks: {
                    success: function (result) {
                        if (result.success) {
                            console.log($scope.posts); //[FIRST OUT]
                            $scope.posts.push(result.post);
                            $scope.title = '';
                            console.log($scope.posts); //[SECOND OUT]
                        }
                    }
                },
                values: { upvotes: 0, downvotes: 0 },
                files: $scope.files
            });
            ...
    }
}]);  

.
HTML

<form action="/Home/FileUp" id="postForm" method="post" enctype="multipart/form-data">
    <div class="form-group input-group">
        <span class="input-group-addon">Post Title</span>
        <input name="title" class="form-control" type="text" data-ng-model="title" />
    </div>
    <ul>
        <li ng-repeat="file in files">{{file.name}}</li>
    </ul>
    <button class="btn btn-primary" type="button" data-ng-click="addPost()">Add New</button>
</form>  

SCREEN


A sample post displayed in the list

.
PROBLEMS

Upon clicking the Add New button for the first time, everything seems to work smoothly until $scope.posts.push(result.post);. The console displays [SECOND OUT]:


The first object has a $$hashKey, but the second object sent from the server (added by the $scope.posts.push(result.post); function) does not have it. This inconsistency leaves me questioning why this is happening. Moreover, upon clicking the Add New button for the second time, everything completes successfully without any new logs appearing in the console, and the newly added post is shown on the list as depicted in the screen image above.

MAIN PROBLEM
Although I pushed the returned value from the server, the post list (on the screen) remains unaffected after the first click.

QUESTIONS
- What exactly is causing this behavior? or
- Where am I going wrong? Any insights would be greatly appreciated.

Answer №1

If you are worried about the $$hashkey, rest assured that you are not doing anything wrong. When using ng-repeat with an array of objects in Angular, a unique key is automatically attached to each item, identified by the property $$hashkey. This key is then used to link DOM elements to their corresponding items based on identity. By rearranging the position of an object within the array, the associated DOM element will also be moved accordingly. To prevent Angular from adding this extra property to the object, you can use track by in conjunction with ng-repeat, providing either a unique key for the object or simply $index. This way, Angular will associate the DOM element with the array item based on the unique identifier you provide.

  ng-repeat="post in posts track by $index"

Alternatively, if each object in the array has a unique id (e.g., id), you can specify:

 ng-repeat="post in posts track by post.id"

Since you mentioned using my xml http request code here, I assume it is outside the Angular context. In such cases, manually triggering the digest cycle with $scope.$apply() becomes necessary.

       $scope.addPost = function () {
        $xhr.reqit({
            form: document.getElementById('postForm'),
            callbacks: {
                success: function (result) {
                    if (result.success) {
                        $scope.posts.push(result.post);
                        $scope.title = '';
                        $scope.$apply();//<-- here
                    }
                }
            },

However, wrapping your xhr implementation with a $q allows you to skip manual $scope.$apply() calls throughout the code. By passing $q promises from your API, the promise chaining will handle the digestion cycle invocation seamlessly.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Manipulate the value of an HTML element's style parameter with jQuery

How do I change an element's style property using jQuery? This is the HTML code I am working with: <div id="template" style="width:200px; height:200px; border:none;">blabla...</div> I attempted to do this: $('#template').attr ...

Which types of characters am I allowed to include in an HTTP response body while using NodeJS and Express?

I am currently developing a node express app that responds to an AJAX post from the client browser. I am curious about what characters would be considered invalid to include in the HTTP response body. My response header specifies the use of charset=utf-8, ...

Why is my Bootstrap Carousel Switching Images but Refusing to Slide?

I've encountered a problem with my bootstrap carousel. The slide effect doesn't seem to be working, even though I have added the "slide" CSS tag. Instead of sliding, the images just quickly change without any transition. Here are some key points ...

Unable to retrieve the content of Material UI Textfield

I'm new to React and I need help with my login page that uses Firebase authentication. I have an input field to capture the user's contact information for validation, but I'm having trouble retrieving this data. I've tried various solut ...

Tips for utilizing the jQuery selectbox plugin on multiple elements within a single page

On my webpage, there are 3 select boxes that I want to customize using a jQuery selectbox plugin. However, the issue I'm encountering is that the plugin only works on the first select box and the others remain unchanged. Does anyone know why this mig ...

Hide popup in React Semantic UI when clicking on a different popup

I've integrated React Semantic UI into my application and I'm using the semantic Popup component to display tooltips. One issue I'm encountering is that when I click on a popup button, previously opened popups are not automatically closing. ...

Detecting changes in URL hash using JavaScript - the ultimate guide

What is the most effective method for determining if a URL has changed in JavaScript? Some websites, such as GitHub, utilize AJAX to add page information after a # symbol in order to generate a distinct URL without having to refresh the page. How can one ...

Navigating through the Table using AngularJS

I was able to successfully loop through a table using AngularJS to retrieve values from a specified scope named {{rec}} as shown below. HTML <div id="AngularContainer" data-ng-app="myApp" data-ng-controller="myCtrl"> < ...

Guidelines for establishing authentic headers on a SignalR connection

Can headers be set on the SignalR connection directly? I am aware of setting query string parameters but it is not secure enough for my specific scenario. var conn = ($ as any).hubConnection(); conn.url = URL; conn.qs = { "token": SECRET_KEY }; conn ...

How to Align Text at the Center of a Line in Three.js

Exploring What I Possess. https://i.sstatic.net/nAtmp.png Setting My Goals: https://i.sstatic.net/svcxa.png Addressing My Queries: In the realm of three.js, how can I transform position x and y into browser coordinates to perfectly align text in th ...

Unable to access current props within useEffect block

When I use useEffect with the parameter props.quizStep, my function fn (which is a keydown event listener) is unable to access the current value of props.quizStep. I'm puzzled as to why it's not working properly. Can you help me understand? Bel ...

Using Jquery to show element when <select> is updated

I've been struggling to make this work due to my limited jquery/js skills. My goal is to have a different message displayed for each option selected from the dropdown menu for further information. <label class="checklabel">Is it possible to re ...

What is the reason that the slick slider is unable to remove the class filter?

Having troubles with my slickUnfilter function, even though slickFilter is working perfectly? Here's a snippet of my HTML: <div class="slider-wrapper" id="wrapper"> <div class="post" id="post1"&g ...

Implementing TSLint in Angular JS: Guidelines for Setup and Customization

For my AngularJs project, the requirement is to use tslint with warnings treated as errors. I followed all the steps on the palantir website () to install tslint: npm install tslint typescript --save-dev -i, --init: - Generates a tslint.json config file ...

Vue JS ensures that it has all the necessary data before proceeding with the

I've been grappling with a VueJS data rendering issue for a few weeks now. My approach involves making axios calls, some nested within others. The problem I'm facing is that the data renders before the calls have completed, resulting in an empty ...

The dynamic form functionality is experiencing issues when incorporating ng-container and ng-template

I'm currently working on a dynamic form that fetches form fields from an API. I've attempted to use ng-container & ng-template to reuse the formgroup multiple times, but it's not functioning as anticipated. Interestingly, when I revert b ...

Saving vast array in MongoDB

I am currently working on a personal project that involves implementing a search feature. My setup includes using typeahead.js with a REST api created in expressJS and mongoDB. I could use some guidance on two particular challenges I am facing. While my ba ...

Is there a way to ensure that the line numbers displayed for JavaScript errors in Chrome are accurate?

I suspect either my webpack configuration or my npm run dev script are causing the issue, but I'm unsure of what exactly is going wrong. While running my application in development mode, I encounter error messages like: Uncaught TypeError: this.props ...

My Angular ng-repeat isn't reflecting changes made by a custom filter

My ng-repeat is filtering out items based on a category selected by the user, but when the page loads with the default 'all' category, none of the items are filtered. There are three categories available and the selected category is passed into a ...

Unpredictable preset inline styles for HTML input elements

While developing a full-stack MERN application, I encountered an unusual issue when inspecting my React UI in Chrome DevTools. If any of these dependencies are playing a role, below are the ones installed that might be contributing to this problem: Tail ...