Struggling to make the upvoting feature function properly in the Thinkster MEAN Stack Tutorial

While following the MEAN Stack tutorial on this website, I decided to modify my code to utilize Controller as instead of using $scope as demonstrated in their examples.

I am encountering an issue with the upvote functionality. Whenever I click to upvote a post, the number of upvotes does not increase, and I'm unsure of what might be causing this problem.

Could anyone provide assistance in resolving this issue? Below is the code snippet for reference:

index.html

<html>
    <head>
        <title>My Angular App!</title>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js"></script>
        <script src="app.js"></script>
    </head>
    <body ng-app="flapperNews" ng-controller="MainCtrl as main">
        <div ng-repeat="post in main.posts | orderBy: '-upvotes'">
            <span ng-click="incrementUpvotes(post)">^</span>
            {{ post.title }} - upvotes: {{ post.upvotes }}
        </div>
        <form ng-submit="main.addPost()">
            <input type="text" ng-model="main.title"></input>
            <button type="submit">Add Post</button>
        </form>
    </body>
</html>

app.js

/*global angular*/
/*jslint white:true*/
angular
    .module('flapperNews', [])
    .controller('MainCtrl', function(){
        'use strict';
        var main = this;

        main.posts = [
            {title: 'post 1', upvotes: 5},
            {title: 'post 2', upvotes: 2},
            {title: 'post 3', upvotes: 15},
            {title: 'post 4', upvotes: 9},
            {title: 'post 5', upvotes: 4}
        ];

        main.addPost = function(){
            if(!main.title || main.title === '') {return;}
            main.posts.push({title: main.title, upvotes: 0});
            main.title = '';
        };

        main.incrementUpvotes = function(post) {
            post.upvotes += 1;
        };
});

Answer №1

The issue at hand pertains to the ng-repeat directive. To resolve it, you will need to modify your code to utilize $parent.incrementUpvotes(post).

Here's the reason behind this adjustment: when using ng-repeat, a new child scope is created for each iteration, limiting access to certain elements. Angular copies properties into the child scope, which can hinder access to definitions such as incrementUpvotes from the controller scope. To overcome this, you must navigate up to the parent scope. Another approach would be to use main.incrementUpvotes(post) if you have assigned an alias for the controller.

To delve deeper into why angular creates child scopes and the limitations on inherited properties, you can refer to this link: https://github.com/angular/angular.js/wiki/Understanding-Scopes

Essentially, the child scope receives its own property that conceals or overrides the parent property with the same name. This behavior is inherent to JavaScript prototypal inheritance rather than a deliberate action by AngularJS. Many novice AngularJS developers encounter difficulties related to directives like ng-repeat, ng-switch, ng-view, and ng-include due to the creation of new child scopes during their usage.

Answer №2

Simply include main.incrementUpvotes(post) in place of incrementUpvotes(post).

angular
    .module('flapperNews', [])
    .controller('MainCtrl', function(){
        'use strict';
        var main = this;

        main.posts = [
            {title: 'post 1', upvotes: 5},
            {title: 'post 2', upvotes: 2},
            {title: 'post 3', upvotes: 15},
            {title: 'post 4', upvotes: 9},
            {title: 'post 5', upvotes: 4}
        ];

        main.addPost = function(){
            if(!main.title || main.title === '') {return;}
            main.posts.push({title: main.title, upvotes: 0});
            main.title = '';
        };

        main.incrementUpvotes = function(post) {
            post.upvotes += 1;
        };
});
<html>
    <head>
        <title>My Angular App!</title>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js"></script>
        <script src="app.js"></script>
    </head>
    <body ng-app="flapperNews" ng-controller="MainCtrl as main">
        <div ng-repeat="post in main.posts | orderBy: '-upvotes'">
            <span ng-click="main.incrementUpvotes(post)">^</span>
            {{ post.title }} - upvotes: {{ post.upvotes }}
        </div>
        <form ng-submit="main.addPost()">
            <input type="text" ng-model="main.title"></input>
            <button type="submit">Add Post</button>
        </form>
    </body>
</html>

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

Having trouble retrieving textfield value with jQuery

On my website, I have an invoice.jsp page that requires jQuery to calculate values in textboxes. Within the invoice, there is a quantity textbox. When a user enters a quantity, the price should be dynamically calculated as (total_subPrice= unit_price * qu ...

`Need help testing flow.js file uploads using Selenium?`

My AngularJS SPA allows users to upload files using the ng-flow wrapper for flow.js. I am currently in the process of setting up automated e2e tests with Selenium, but I am facing challenges when it comes to testing the file uploading mechanism triggered b ...

Can the grunt command be executed automatically after saving code in TypeScript?

As a newcomer to FrontEnd and JavaScript coding in TypeScript, I find myself constantly needing to follow these steps after making a code change: save the code -> compile it using Grunt -> reload the webpage. It can be quite time-consuming. Is there ...

CarouFredSel Transition Troubles

I am currently using CarouFredSel to create an image carousel, but I am encountering some issues with the transitions between items. My goal is to incorporate simple HTML elements into the carousel instead of just plain images. However, when I attempt to ...

Prevent the selection of Single Origin and House Blend options once the user opts for Espresso

<td> <select class="type"> <option value="Espresso">Espresso</option> <option value="" class="">Cappuccino</option> <opti ...

Associate the callback function with a directive that does not have an isolated scope

Ensuring the correct context when binding a callback function to a directive is crucial. When working with an isolated scope, this task is easily accomplished. <bar-foo callback="mycontroller.callback()"></bar-foo> The directive code: ... ...

Looking to fill a text field with email addresses by selecting checkboxes for various towers

I have 4 towers and I need checkboxes for each of them. Upon checking any combination of them, the 'txtNotifTo' textbox should be populated with the respective group of email IDs for each tower selected. Could you please assist me in identifying ...

In JavaScript, Identify the filename selected to be attached to the form and provide an alert message if the user chooses the incorrect file

I have a form in HTML that includes an input field for file upload. I am looking to ensure that the selected file matches the desired file name (mcust.csv). If a different file is chosen, I want to trigger a JS error. Below is the form: <form name="up ...

What is the recommended approach for conducting backend validation?

As I develop a CRUD application using express.js and node.js, here is the backend API code that I have written: app.post("/signup", (req, res) => { const { name, email, password } = req.body; if (!name) { res.status(401).json("Please provide a n ...

Tips for utilizing the onload attribute alongside the ng-controller directive to run a function that has been established within the controller

When trying to call the submit() function as soon as the page loads, I keep encountering a submit() method not found error. The positioning of ng-controller and onload is confusing to me. If there is an alternate method in Angular to achieve this, please ...

What techniques can I use to generate a 3D visual effect by shifting the background image layer as the user scrolls (creating a Parallax effect

I have combined two images in the heading; one on top of the other. My goal is to create a subtle vertical movement in the background image as the user scrolls, giving the illusion of depth. Both images share the same width, but the background image is tal ...

Implementing JSON data retrieval in Django through jQuery

i have implemented a jQuery functionality to send json data containing arrays of elements as shown below $('#brand_category').click(function(event){ category = $("input:checkbox[name=category]:checked").map(function() { return t ...

Is it possible to create a button function in HTML that can alter the CSS image tag?

Is there a way I could create a function that can retrieve a value, update an image source, and then incrementally select another value? It would be incredibly helpful if you could provide a reference where I could learn how to do this or explain it in det ...

Interpret data from an external JSON file into a HighCharts chart using JavaScript

Currently, I am exploring the process of incorporating HighCharts Chart data directly within the actual webpage. Below is the complete code snippet: <!DOCTYPE html> <html><head> <script type="text/javascript" src="http://code.jquery. ...

Implementing dynamic active class changes in a navbar with JavaScript

My goal was to have the navbar change its class to 'active' dynamically when a user clicks on the <li> tag. Can you help me pinpoint where I made a mistake? dynamicNavbar(); function dynamicNavbar() { $('.nav_w3ls .menu a'). ...

Conceal a row in a table using knockout's style binding functionality

Is it possible to bind the display style of a table row using knockout.js with a viewmodel property? I need to utilize this binding in order to toggle the visibility of the table row based on other properties within my viewmodel. Here is an example of HTM ...

Tips for displaying HTML content using an array in Vue JS

Hi, I'm a beginner with Vue JS and I'm working on passing an HTML table using this array. I have a dropdown where I can select the option I want, but I'm struggling to figure out how to include HTML within it. Whenever I try, it ends up disp ...

Display the table upon completion of the form submission

I am trying to create a form where the table #mytable is only displayed after the form has been submitted. If nothing is entered in the form, the table should remain hidden. Any suggestions on how I can achieve this? <form action="" id="myform" method ...

Tips for displaying previous values when discarding changes to a record in a material-ui table

How can I prevent changes from reflecting in a material-ui table when clicking on the X icon while editing a row? Is there a way to only save the edited record on the check (_) icon instead? Any suggestions or solutions would be greatly appreciated as I am ...

Making a Dialog resizable with jQuery's Resizable Helper

Is there a way to implement the Helper feature from jQuery Resizable, which only shows a frame while resizing the container, in a Dialog? ...