Angular ng-model won't pass - javascript

I'm working on an app, and am trying to pass a string through ng-model like I do in other places. But this one always returns "undefined".
HTML:
<aside>
<p>List of objs:</p>
<ul>
<li class="objList" ng-repeat="obj in objs">
{{ obj.topic }}
<div class="appear" ng-show="hideBool2">
X
<input class="uName" ng-model="passWo" placeholder="Password">
<button class="btn btn-default" ng-click="connectTo(obj.info)">OK</button>
<p ng-bind="message"></p>
</div>
</li>
</ul>
</aside>
Controller function used:
$scope.connectTo = function(rName) {
alert($scope.rooms[rName].password + " " + $scope.passWo)
if($scope.rooms[rName].password != "") {
if($scope.rooms[rName].password == $scope.passWo) {
socket.emit("joinroom", { room: rName, pass: $scope.passWo }, function(success, errorMessage) {});
$location.path("/room/" + rName);
}else{
$scope.message = "Wrong password";
}
}else{
alert($scope.rooms[rName].password);
}
}
but the $scope.passWo always returns undefined.
Everything else works in the code.
Any help would be appreciated.

The problem is that the ng-model is assigning the value to its internal $scope. So when you call the connectTo function, it finds the $scope.connectTo in the controller scope, but the use of $scope.passWo, can't find the value, as ng-repeat creates a scope for each item.
The easiest way to overcome this (if you want to use a single scope value) is to create a container object inside the controller:
$scope.cont = { passWo: '' };
Then inside your view, use:
ng-model="cont.passWo"
This article might help you: http://jimhoskins.com/2012/12/14/nested-scopes-in-angularjs.html

Related

How to pass value into ng-if after ng-click?

Purpose
I am trying to get admin and customer show in different stages, admin can post the data after clicking the toggleShowDiv(), which allows customer to see the data.
Question
How to pass !isAdmin() into ng-if? Currently, I am only getting isAdmin as default.
Is able to post it into table TD by TD (row by row)? not sure, I am writing the correct code here.
My thought
Can I use ng-if to each single TD = isAdmin() or !isAdmin, and control by a click function?
$scope.showDiv = isAdmin();
$scope.toggleShowDiv = function (auction) {
var title = 'text.......';
var text = 'are you sure?';
ConfirmModal(title, text, function () {
$scope.showDiv = !isAdmin() ;
});
};
HTML
<div ng-if="showDiv">
<tbody class="auction-group" ng-repeat="a in foos">
<td ng-if="isAdmin()">
<input type="checkbox" ng-click="toggleShowDiv()" />
</td>
</div>
Update
isAdmin() is just a function that passed from the backend.
function isAdmin() {
return !!($aScope.currentUser && $aScope.currentUser.isAdministrator);
}
Please note: the question is not about the isAdmin() function, it works fine. What I want to do is to use a click function to show and hide the table row.
Have a look at this. Here you have 2 users online at the same time, dude1 (admin) and dude2 (non admin). You can toggle the display from the admin side for the non admin side by having a call to the back end that continuously checks if the display is valid or not. For putting a toggle on the table rows you need to just add the ng-if to the <tr> elements.
var app = angular.module('app', []);
app.controller("controller", function($scope) {
$scope.dude1 = {admin: true, name: [{name: 'A+', country:'India', publish: true}, {name: 'A', country:'Unknown', publish: true}]};
$scope.dude2 = {admin: false, name: [{name: 'A+', country:'India', publish: true}, {name: 'A', country:'Unknown', publish: true}]};
$scope.toggler = (index) => {
$scope.dude1.name[index].publish = !$scope.dude1.name[index].publish;
};
$scope.names = (dude) => {
return dude.name;
};
setInterval(() => {
/**
* Any backed function to get and repopulate the data.
* Update the value of publish from the server. I'm just using
* the other guys data. But you should fetch it from the server.
*/
$scope.dude2 = valfromServer();
// console.log($scope.dude2, $scope.dude1);
}, 2000);
var valfromServer = () => {
return {
admin: false,
name: $scope.dude1.name
};
};
$scope.publish = (dude, index) => {
return dude.admin || dude.name[index].publish;
};
$scope.isAdmin = (dude) => {
return dude.admin;
};
});
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.6.0" data-semver="1.6.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.js"></script>
</head>
<body ng-app="app" ng-controller="controller">
<span>Admin Panel</span>
<div>
<table style="width:40%">
<tr ng-repeat="x in names(dude1)" ng-if="publish(dude1, $index)">
<td>{{ x.name }}</td>
<td>{{ x.country }}</td>
<td>{{ $index }}</td>
<td><button ng-click="toggler($index)" ng-if="isAdmin(dude1)">Publish</button></td>
</tr>
</table>
</div>
<hr>
<span>Non admin panel</span>
<div>
<table style="width:40%">
<tr ng-repeat="x in names(dude2)" ng-if="publish(dude2, $index)">
<td>{{ x.name }}</td>
<td>{{ x.country }}</td>
<td>{{ $index }}</td>
<td><button ng-click="toggler($index)" ng-if="isAdmin(dude2)">Publish</button></td>
</tr>
</table>
</div>
</body>
</html>
<div ng-if="showDiv == true || isAdmin == true">
<tbody class="auction-group" ng-repeat="a in foos">
<td ng-if="isAdmin == true">
<input type="checkbox" ng-click="toggleShowDiv()" />
</td>
</div>
JS code Let say first any one who enters will be customer
$scope.showDiv = false;
$scope.isAdmin = false;
now when response comes form backend check the response and change the value of $scope.isAdmin accordingly.
if(response == admin){
$scope.isAdmin= true;
}else{
$scope.isAdmin = false;
}
now in onclick checkbox function
$scope.toggleShowDiv = function (auction) {
var title = 'text.......';
var text = 'are you sure?';
ConfirmModal(title, text, function () {
if($scope.showDiv == false){
$scope.showDiv = true;
}else{
$scope.showDiv = false;
}
});
};
Well I think that you should use some var that change according if the user click like $scope.showTable = true /false. But not complety sure about your real need.
I am confused on your question -
I will suggest few points, i hope it will help you -
ng-if is a inbuilt directive. You can use it on any DOM element. You can control it by using attribute or function, only need to pass Boolean attribute to this directive. Eg:
ng-if="showHideAttribute" or ng-if="functionNameWhichReturnBoolean()"
Scope - if you are clicking on button/checkbox/ng-click applied element is available in the same scope of applied ng-if directive then no problem. Otherwise you need to use service or observers (on/emit/broadcast) or rootScope then only it will work.
I hope you are receiving isAdmin = true/false from backend in your function. So, i am thinking this is the problem of scope.
Instead of ng-if="showDiv" use something link ng-if="obj.showDiv"
In the controller define $scope.obj = {};
The issue is ng-if creates its own scope, so always pass data as an object because objects in JS are passed by reference.
You can do this
ng-if = "isAdmin == false"
You're really confusing me, but if I understood correctly, it is something like this you want?
First things first, your HTML is truely horrible, parts of tables in divs? Don't do that...
Secondly, don't hack kabout with the isAdmin to toggle things.
isAdmin should only be used to check if a user is an admin.
You can however create another variable that instantiates to the same value, and use that one to toggle stuff.
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
this.content = 'This is some unpublished content, only the admin can view, unless you\'ve now gone and publish it.';
this.isPublished = false;
this.isAdmin = false;
});
/* Put your css in here */
textarea,
label,
button {
display: block;
margin: 15px 15px 0 0;
}
button {
display: inline-block;
}
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
<div ng-app="plunker">
<div ng-controller="MainCtrl as $ctrl" ng-init="$ctrl.isAdmin=false">
<article>
<section class="content">
<section ng-if="$ctrl.isAdmin || $ctrl.isPublished">{{ $ctrl.content }}</section>
<section ng-if="!$ctrl.isAdmin && !$ctrl.isPublished"><pre>-- no published content found --</pre></section>
</section>
<section class="admin-only" ng-if="$ctrl.isAdmin">
<label><input type="checkbox" ng-model="$ctrl.isPublished"> publish article</label>
</section>
</article>
<hr />
<label><input type="checkbox" ng-model="$ctrl.isAdmin"> is admin</label>
</div>
</div>
edit:
You're still confusing me, but does this come closer to what you want / need?
What i understand is, "When admin trigger some action i.e. ng-click, user should be able to see that data/changes."
If this is the case, consider following:
I'm damn sure that this is not going to happen on the same machine.
Admin will be using the application on his machine from where it'll
do some action i.e. ng-click will gets fired and some data will gets
changed on server.
Now there will be (n) number of users using the application from
their machines. How they will get to know about the change which admin has made?
In such scenario, when there is changes on server and
client(browser) should be aware of that we make use of socket.io,
which listens to events from server and refreshes itself when there
is some changes on server state or we can say, when admin has
triggered some action i.e. ng-click.
Let me know, if you have any queries.
Thanks

How can I correctly use variable variable names in ng-repeat in angular?

HTML:
<ul>
<li ng-repeat="comic in comiclist">
<span>{{ comic.title }} : {{comic.id}}</span>
<div >
<img ng-src="{{comic.thumbnail.path}}.{{comic.thumbnail.extension}}"/>
</div>
<div>
<ul>
<li ng-repeat="character in charlist + {{comic.id}}">
<span>{{character.name}}</span>
</li>
</ul>
</div>
</li>
</ul>
JS with angular
var App = angular.module('MarvelApp', []);
App.controller('MainController', function($scope,$window, $http) {
$scope.GetSeries = function(){
$http.get('http://gateway.marvel.com/v1/public/series?')
.then(function(response){
$scope.serieslist = response.data.data.results;
});
};
$scope.GetComics = function(){
$http.get('http://gateway.marvel.com/v1/public/series/' + $scope.selectedseries + '/comics?')
.then(function(response){
$scope.comiclist = response.data.data.results;
});
//comic in comiclist contains comic.id
//which needs to go to GetCharacter()
}
$scope.GetCharacter = function(comicid){
$http.get('http://gateway.marvel.com/v1/public/comics/' + comicid + '/characters')
.then(function(response){
$scope.['charlist' + comicid] = response.data.data.results;
//this list needs to be displayed in the second ng-repeat
});
};
});
I'd like to get the character list to display in the right div. How I had it set up before, (without $scope.['charlist' + comicid]) it was overriding the other ng-repeats too.
Also, whenever GetComics() gets called it does it automatically.
I don't think $scope.[] is valid syntax (unless I've been missing out on a nifty trick).
You should instead name an "associative array" under $scope something like:
$scope.charlist[comicid] = ... ;
Your ng-repeat would then look something like:
<li ng-repeat="character in charlist[comic.id]">
EDIT As mentioned in the comments, $scope.charlist must be defined before the above lines can be used. This can happen in a few ways:
Make a check before you set it: if(!$scope.charlist) $scope.charlist = [];
Define it somewhere in the controller with $scope.charlist = [];
Of course there's any number of ways you can do this, but these make these I believe make the most sense, the first of which catches invalid states i.e. if for some reason $scope.charlist is set to null it would create a new "associative array".

Duplicate in ng-repeat error

Hello for some reason it says as a error:
Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: mes in messagess, Duplicate key: string:f, Duplicate value: f
But i dont understand why, i personally dont see any duplicates...
Here is my Cloud9 File to see the code and make changes...
Here is my Chat.html:
<h1 style = "text-align:center; position:relative; left:-80px"> Universal Chat </h1>
<div id = "rectangle" >
<ul id="example-messages" class="example-chat-messages">
<li ng-repeat = "mes in messagess">
{{mes}}
</li>
</ul>
</div>
<textarea class="form-control" id="chatbox" rows="1" ng-model = "textValue">
</textarea>
<a class="btn right" id = "submitButton" ng-click = "submit()">
<span class="left title">Submit Comment</span>
<span class="right icon icon-comment"><span class="slant-right"></span></span>
</a>
And my chatController.js:
app.controller('chatController', ["$scope", 'AuthService', "Auth", "Ref", "$rootScope", "$firebaseArray", "$firebaseObject",
function($scope, AuthService, Auth, Ref, $rootScope, $firebaseArray, $firebaseObject) {
var postsArray = {}
console.log(AuthService.User.email) //Gives me correct Email
console.log(AuthService.User.password) //Gives me correct password
console.log(AuthService.User.uid) //Gives me correct uid
console.log(AuthService.User.username) //Gives me correct username
some = $firebaseArray(Ref.child("Posts").child(AuthService.User.username));
console.log((some))
var postsFirebase = $firebaseObject(Ref)
var username = AuthService.User.username
$scope.messagess = {}
$scope.submit = function() {
if (!($scope.textValue)) {
}
else {
some.$add({
Posts: $scope.textValue
}).then(function(authData) {
console.log(authData.path)
Ref.child("Posts").child(username).child(authData.path.o[2]).on("value", function(snapshot) {
console.log(snapshot.val().Posts)
$scope.messagess.push(snapshot.val().Posts)
snapshot.val().Posts
}, function(errorObject) {
console.log("The read failed: " + errorObject.code);
});
}).catch(function(errorObject){
alert("See the console for more details")
console.error(errorObject.code)
})
}
}
}
])
SnapShot.val is like the current post you submitted in my firebase here:
This is not a duplicate. Those methods from other places didnt work..
The duplicate error says its f duplicated, so I suppose the messages is a string, not an array. What you are trying to do is to display every message. But now, you are iterating over the message itself, that is:
<li ng-repeat="mes in 'message'">
Which takes m for the first item, e for second, s fot the third. And, as you may suppose, it will throws the error when it notices the next (duplicated) s.
You should iterate over array of messages, i.e.:
<li ng-repeat="mes in ['message']">
Which will display them correctly. Please review what is saved to the scope in this line:
$scope.messagess = snapshot.val().Posts
It should be an array.
However, please note that after fixing it you should still use the track by as posting the same message twice will tirgger the error again.
<li ng-repeat="mes in messages track by $index">
Related: Angular ng-repeat Error "Duplicates in a repeater are not allowed."]
If you still have the problem, please try to create Minimal, Complete, and Verifiable example so we can help.
UPDATE:
Based on the screen of data structure you provided (the Posts is string as I supposed), you should change the scope assignment to:
$scope.messagess = snapshot.val()
and then, in the view, read all values, i.e.
<li ng-repeat="mes in messages">{{ mes.Posts }}</li>
However, I find this structure (and naming) weird.

How to change text in this case using ng-if or other expression?

I'm trying to change the text in a title tag based on a tag's direction value:
<li ng-repeat="t in tags">
<div class="tag"
ng-class="{'green-up': t.direction == 'positive',
'red-down': t.direction == 'negative',
'' : t.direction == 'stagnant'}"
title="Percentage increase"
ng-if="">{{t.name}}</div>
</li>
The direction is either positive, negative or stagnant, which should correspond to title="Percentage increase" title="Percentage decrease" or just title="Percentage"
What Angular syntax would be best used in this case?
Why not set up the tag settings as an object
$scope.tagInfo = {
positive:{ class:"green-up", title:"Percentage increase" },
negative:{ class:"red-down", title:"Percentage decrease" }
}
and then call that in your ng-repeat
<div class="tag"
ng-class="tagInfo[t.direction].class"
title="{{tagInfo[t.direction].title}}">{{t.name}}</div>
http://jsfiddle.net/rLrh0Lr1/
If you absolutely positively must use a conditional clause rather than a mapping lookup, call a method like f.e title="{{getTitle(t.direction)}}
$scope.getTitle = function(direction) {
if (direction==="positive") {
return "Increase";
} else if (direction==="negative") {
return "Decrease";
}
};
http://jsfiddle.net/p6aysky5/
I don't really see the point at all of doing that though. All it contributes is making your code messier.

Update unrelated field when clicking Angular checkbox

I have a list of checkboxes for people, and I need to trigger an event that will display information about each person selected in another area of the view. I am getting the event to run in my controller and updating the array of staff information. However, the view is not updated with this information. I think this is probably some kind of scope issue, but cannot find anything that works. I have tried adding a $watch, my code seems to think that is already running. I have also tried adding a directive, but nothing in there seems to make this work any better. I am very, very new to Angular and do not know where to look for help on this.
My view includes the following:
<div data-ng-controller="staffController as staffCtrl" id="providerList" class="scrollDiv">
<fieldset>
<p data-ng-repeat="person in staffCtrl.persons">
<input type="checkbox" name="selectedPersons" value="{{ physician.StaffNumber }}" data-ng-model="person.isSelected"
data-ng-checked="isSelected(person.StaffNumber)" data-ng-change="staffCtrl.toggleSelection(person.StaffNumber)" />
{{ person.LastName }}, {{ person.FirstName }}<br />
</p>
</fieldset>
</div>
<div data-ng-controller="staffController as staffCtrl">
# of items: <span data-ng-bind="staffCtrl.infoList.length"></span>
<ul>
<li data-ng-repeat="info in staffCtrl.infoList">
<span data-ng-bind="info.staffInfoItem1"></span>
</li>
</ul>
</div>
My controller includes the following:
function getStaffInfo(staffId, date) {
staffService.getStaffInfoById(staffId)
.then(success)
.catch(failed);
function success(data) {
if (!self.infoList.length > 0) {
self.infoList = [];
}
var staffItems = { staffId: staffNumber, info: data };
self.infoList.push(staffItems);
}
function failed(err) {
self.errorMessage = err;
}
}
self.toggleSelection = function toggleSelection(staffId) {
var idx = self.selectedStaff.indexOf(staffId);
// is currently selected
if (idx >= 0) {
self.selectedStaff.splice(idx, 1);
removeInfoForStaff(staffId);
} else {
self.selectedStaff.push(staffId);
getStaffInfo(staffId);
}
};
Thanks in advance!!
In the code you posted, there are two main problems. One in the template, and one in the controller logic.
Your template is the following :
<div data-ng-controller="staffController as staffCtrl" id="providerList" class="scrollDiv">
<!-- ngRepeat where you select the persons -->
</div>
<div data-ng-controller="staffController as staffCtrl">
<!-- ngRepeat where you show persons info -->
</div>
Here, you declared twice the controller, therefore, you have two instances of it. When you select the persons, you are storing the info in the data structures of the first instance. But the part of the view that displays the infos is working with other instances of the data structures, that are undefined or empty. The controller should be declared on a parent element of the two divs.
The second mistake is the following :
if (!self.infoList.length > 0) {
self.infoList = [];
}
You probably meant :
if (!self.infoList) {
self.infoList = [];
}
which could be rewrited as :
self.infoList = self.infoList || [];

Categories