angular directives comment section - angularjs

I am working on a website that displays numerous articles. Each article has a comment section. I have effectively been able to recursively write the comments to the DOM with recursion inside an ng-repeat. However, I need to be able to click on a respond button on any of the comments (they display in a nested fashion) and for a div to be inserted beneath the clicked button. This div would contain a text area for the comment they want to submit and a button. When this second button is clicked, the controller will save the comment to the database. I initially wanted to do this by directly manipulating the DOM from the controller. However, after further research, that would be in direct violation of the MVC/MVW pattern. I believe the correct answer is to create a custom directive. Please give me some insight on how to correctly do this. Any and all information would be very helpful. Thanks in advance.

If you want to add response div dinamically:
<div ng-repeat="article in articles" id="article-{{$index}}">
<p>{{article.content}}</p>
<button ng-click="addAnswer($index)">Add Answer</button>
</div>
js:
myApp.controller("articlesController", function($compile){
$scope.addAnswer = function (index) {
var div = $("<div></div>");
var input = $("<input type='text' ng-model='article.response'></input>");
div.append(input);
var button = $("<button>Send</button>");
button.attr("ng-click", "sendResponse(article)");
$compile(div)($scope);
$("#article-" + index).append(div);
};
});

You don't really need to make a directive to achieve this.
html:
<div ng-repeat="article in articles">
<p>{{article.content}}</p>
<input type="text" ng-model="article.response"></input>
<button ng-click="sendResponse(article)">Send</button>
</div>
js:
myApp.controller("articlesController", function($http){
$scope.sendResponse = function (article) {
console.log(article.response);
$http.post(url, article);
};
});
Of course, you can do it better by hidding input and send button, and show it after user clicks over an answer button.

Related

$anchorScroll is not working in AngularJs

I am working on an app that submits the form and get the result from the server which followed by HTML table view. My input form is a bit big which covers whole the screen. When the table comes then I want automatically scroll down at the table view. I used $anchorScroll from angularJs. But I am not able to achieve the result what I want. I also used $timeout to make sure the table is already exist or not and then perform $anchorScroll, but still no success. (based on this solution : Using $location and $anchorScroll to scroll a table row into view
Hear is my code.
HTML
<div data-ng-controller="searchController as searchCtrl" id="scrollArea">
<form>
//HTML input elements
<div class="buttons">
<md-button class="md-primary md-raised" ng-click="searchCtrl.gotoTable('resultTable')">Start</md-button>
</div>
</form>
</div>
<!-- Smart Table for displaying result -->
<div class="rtable" ng-show = "searchCtrl.tableViewData.length > 0" id="resultTable">
//table content
</div>
Controller
angular.module('myApp')
.controller("searchController", function($log, searchService, $scope, $location, $anchorScroll, $timeout){
var self = this;
self.gotoTable = function(resultTable)
{
$timeout(function() {
$location.hash(resultTable);
$anchorScroll();
});
};
});
I dont know why its not working?
Do i need to define the id scrollArea and resultTable in my CSS?
Any help would be appreciated.
Thanks in advance.
UPDATE
Based on Okazari's solution, I tried to put a another div with many br tag above at the very bottom of my HTML. Now When I refresh the page then it automatically scroll to that div tag without clicking Start. this is a bit weird. I also tried to cover the
<div class="rtable" ng-show = "searchCtrl.tableViewData.length > 0" id="resultTable">
tag with another div tag with id = "resultTable".
But still it did not work.
You actually are invoking your function without any parameters
ng-click="searchCtrl.gotoTable()"
whereas in your controller you expect to have one :
self.gotoTable = function(resultTable)
Try something like this
ng-click="searchCtrl.gotoTable('resultTable')"
or this :
self.gotoTable = function()
{
$timeout(function() {
$location.hash("resultTable");
$anchorScroll();
});
};
(just one, not both)
Hope it helped.
EDIT : Pretty sure that you can't go to a hidden div. As i said in comment your ng-show may be evaluated to true when you try to anchorscroll().
Here is a working plunker without ng-show. I'll build a tiny solution to avoid the ng-show issue.
To avoid this side effect, i wrapped the div with ng-show with another div.
<div id="resultTable">
<div class="rtable" ng-show = "searchCtrl.tableViewData.length > 0">
</div>

I need to access a radio button array in angularjs

All of the examples I have found show the radio button group being built by some for item in items loop but none of them show a simple accessing of the radio button group array in the angularjs controller. What I need to do is traverse through the button group array to see if any of them are in "selected" state.
var radioSelected = false;
for(var i =0; i < items.length; i++) {
if(items[i].selected) {
radioSelected = true;
}
}
I have tried binding to the ng-model and accessing it .. I have tried using $scope.ButtonGroupName Nothing yeilds an array that I can traverse with a loop. Any suggestions on how to do this once VERY simple activity would be greatly appreciated.
Gotta love being forced to relearn web development because somebody broke out a new shiney hammer.
You would not traverse the DOM elements. You would use the same ng-model for all the radio elements, and that would be updated whenever you change the selected state of the radio button.
<input type="radio" ng-model="assignedValue" name="myRadio" value="one">
<input type="radio" ng-model="assignedValue" name="myRadio" value="two">
<input type="radio" ng-model="assignedValue" name="myRadio" value="three">
You would $watch the $scope.assignedValue for changes instead of traversing the DOM elements.
$scope.$watch('assignedValue', function (newValue, oldValue) {
..do stuff here
});
See here for documentation: https://docs.angularjs.org/api/ng/input/input%5Bradio%5D
The reason you don't traverse the DOM is because it's constantly changing. The whole point of Angular is to work off of data and not the elements themselves.
Update: Based on your comments, it sounds like only want to execute an action if a radio button has been selected.
First, a radio button should always have a selected state. Let's pretend it doesn't though. You can enable / disable / show / hide elements in angular in a couple of ways without writing additional DOM manipulation code.
Taking the example above, this button will only be enabled if the assignedValue is two.
<button ng-disabled="assignedValue != 'two'">My button</button>
You can also conditionally include content using ng-if:
<div ng-if="assignedValue == 'two'>
My conditional content
</div>
This will also work with ng-switch
<div ng-switch on="assignedValue">
<div ng-switch-when="two">My additional content</div>
<div ng-switch-default>Here's switch fallback content</div>
</div>

AngularJS's ng-model icm textarea

I'm trying to add some text to the last cursor place after clicking a button.
In the controller:
$scope.addEmoji = function(name){
var element = $("#chat-msg-input-field");
element.focus(); //ie
var selection = element.getSelection();
var textBefore = $scope.chatMsg.substr(0, selection.start);
var textAfter = $scope.chatMsg.substr(selection.end);
$scope.chatMsg = textBefore + name + textAfter;
}
$scope.updateChatMsg = function(chatMsg){
$scope.chatMsg = chatMsg;
}
$scope.sendChatMsg = function(){
var backend = $scope.convs[$scope.active.conv].backend.name;
$scope.view.addChatMsg($scope.active.conv, $scope.active.user, $scope.chatMsg,new Date().getTime() / 1000, backend);
Chat[backend].on.sendChatMsg($scope.active.conv, $scope.chatMsg);
$scope.chatMsg = '';
};
And then some HTML:
<div class="chat-msg-button" >
<button ng-click="view.toggle('emojiContainer')" ><img src="/apps/chat/img/emoji/smile.png"></button>
</div>
<form id="chat-msg-form" ng-submit="sendChatMsg()">
<div class="chat-msg-button" >
<button type="submit"><div class="icon-play"> </div></button>
</div>
<div id="chat-msg-input">
<textarea id="chat-msg-input-field" autocomplete="off" type="text" ng-model="chatMsg" ng-change="updateChatMsg(chatMsg)" placeholder="Chat message"></textarea>
<div>{{ chatMsg }}</div>
</div>
</form>
What I'm trying to achieve: a user types some text in the textarea => $scope.chatMsg gets the value of the textarea. Now the user press one of the button's => the name of the button is added to the latest cursor position. (it's no problem to find the latest cursor position)
The problem
There is a difference between the value of $scope.chatMsg, {{ chatMsg }} inside the div and the text in the textarea.
The contents of the textarea and the div stays always the same. But when pressing the button the name is added to $scope.chatMsg but the contents of the textarea isn't changed...
How can I solve this?
TIA
First of all, you're mixing jQuery with AngularJS, it doesn't look like you need jQuery here that much.
Also, your chat message is updated in 3 different functions, so you need some debugging to see which are fired.
In general:
To solve your issue, try some more debugging, do a
$scope.$watch($scope.chatMsg, function(){
console.log($scope.chatMsg);
});
this will watch all changes to chatMsg. Add console.log() to each of your functions and you can watch which is fired.
Also, rather than using {{ }} inside your div just use ng-bind since that text is the only item in your div, it's cleaner if your app crashes somewhere.
// change from
<div>{{ chatMsg }}</div>
// to
<div ng-bind="chatMsg "></div>
Update: after seeing your plunker, I modified it and came up with this: http://plnkr.co/edit/oNKGxRrcweiJafKCm9A5?p=preview
Your ng-repeat needs to be tracked by $index so that duplicates are displayed rather than crashing when someone creates the same message
I solved all problems. The plunkr form above works. So after investigating all scopes with the Angular chrome extension I saw that chatMsg was defined in another scope. Thus not in the scope I was trying to acces it from.
Via this question angularJS ng-model input type number to rootScope not updating I found a solution.
I added chatMsg to the fields object.

AngularJS: create element dynamically

How do I go about create an element in my controller? e.g. on a click event?
example controller:
function AddCtrl($scope){
$scope.add = function(){
// do stuff to create a new element?
}
}
example view:
<div ng-controller="AddCtrl">
<button ng-click="add()">Add</button>
// create <input type="text" ng-model="form.anotherField">
</div>
Any suggestions much appreciated.
AngularJS is intended to follow MVC - so the controller creating an element in the view doesn't agree with the MVC behavior. The controller should not know about the view.
It sounds as if you want to have a control appear based on some conditional logic. One approach would be to bind to the visibility of the element.
In Angular, your controllers should not be manipulating the DOM directly. Instead, you should describe the elements you need in your templates, and then control their display with directives, like ng-switch, ng-hide / ng-show, or ng-if, based on your model, ie, your data.
For example in your controller you might do something like:
$scope.showForm = false;
And then in your partial:
<div id="myForm" ng-show="showForm">
<!-- Form goes here -->
</div>
By switching $scope.showForm between true and false, you will see your myForm div appear and disappear.
This is a classical mistake coming from jQuery moving to Angular or any other MVC library. The way you should think is to let the view react to changes in the scope.
$scope.items = []
$scope.add = function(){
$scope.items.push({});
}
In the view:
<input type="text" ng-repeat="item in items" ng-model="item.property">
If you want to display an element based on some condition or after the click, use ng-switch: http://docs.angularjs.org/api/ng/directive/ngSwitch
If you want to add multiple elements, create a repeated list of items and add an item to your view-model on clicking the button:
$scope.yourlistofitems = [];
$scope.add = function() {
$scope.yourlistofitems.push("newitemid");
}
And in the HTML:
<input type="text" ng-repeat="item in yourlistofitems" ng-model="item.property">

How to create set of div blocks using AngularJs

I am newbie to AngularJs. I need to create set of div blocks (given as code) on button click.
<div>
<div>Div A</div>
<div>Div B</div>
<div>Div C</div>
</div>
I have done this using hard coded divs Demo. But I just need to use ng-repeat and directives. Any help will be appreciated.
Using ng-click is the way to go for binding the click event to your button. You should not be trying to handle button clicks with a directive. The demo you have is very close to what you need. There is a working Plunk HERE, but the general guts of it follow:
<button ng-click="myFunction()">Add</button>
<div ng-repeat="item in myList">
<div>{{item.A}}</div>
<div>{{item.B}}</div>
<div>{{item.C}}</div>
</div>
$scope.myList = [];
$scope.myFunction = function(){
var myItem = {A:someValue, B:someOther, C:someThing};
$scope.myList.push(myItem);
};
The divs that hold the items could also make use of directives to change them somehow, but that is quite a bit more code. There are plenty of SO answers and Angular documentation that show you how to write directives, so I won't repeat them here.

Resources