Create a new scope outside ng-repeat - javascript

The idea is how a list of texts can be modified by pressing the button next to the text. We can also apply it to the title text which is outside the list.
HTML:
<div ng-controller="TextController">
<div class="title">
<span>{{ text }}</span>
<button ng-click="edit()">Edit</button>
</div>
<ul>
<li ng-repeat="text in list">
<span>{{ text }}</span>
<button ng-click="edit()">Edit</button>
</li>
</ul>
</div>
JavaScript:
angular.module("app").
controller("TextController", function($scope) {
$scope.text = "hello";
$scope.list = [....]; // list of texts;
$scope.edit = function() {
this.text += " world";
};
});
I'm not sure if I wrote it the right way. However, everything works fine except the edit button in the title which is when I'm trying to edit the title only, it accidentally edits all text which is in its children scope.
What I'm trying to do is to give the title a new scope so that the button doesn't affect other texts because it isn't a parent of any scope.

Yeah What you are trying to do is right:
The {{text}} variable is bound to the same controller scope. so the edit button just updates that value which makes it to change everywhere

You should try to update $scope.list value:
When you updated the scope, the html will render.
$scope.edit = function() {
$scope.list[this.$index] += " world";
};
Please check the demo:
http://jsfiddle.net/Lvc0u55v/7050/

Why don't you use another variable name for ng-repeat(i have made second text => txt). It is better to have separate functions for updating list and text, but if you want, you can try
<div ng-controller="TextController">
<div class="title">
<span>{{ text }}</span>
<button ng-click="edit()">Edit</button>
</div>
<ul>
<li ng-repeat="txt in list">
<span>{{ txt }}</span>
<button ng-click="edit($index)">Edit</button>
</li>
</ul>
</div>
The view is passing $index of the array element:
$scope.edit = function(listIndex) {
if(listIndex) $scope.list[listIndex] += " world"
else $scope.text += " world";
};

You could create an "include" combined with an ng-template so that you get a new scope.
http://jsfiddle.net/pfeq0mwe/3/
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-include src="'myTemplate.htm'">
</div>
<ul>
<li ng-repeat="text in list">
<span>{{ text }}</span>
<button ng-click="edit()">Edit</button>
</li>
</ul>
<script type = "text/ng-template" id = "myTemplate.htm">
<div class="title">
<span>{{ text }}</span>
<button ng-click="edit()">Edit</button>
</div>
</script>
</div>
<div >
</div>

Related

Target only 1 button in Angular

Im getting the values in a div from the DB and displaying using ng-repeat:
<div ng-controller = "myTest">
<div ng-repeat="name in names">
<h4>{{name.name}}</h4>
<button ng-class="{'active': isActive}" ng-click="test()" >me</button>
</div>
</div>
In my controller I have:
$scope.test= function(){
$scope.isActive = !$scope.isActive;
}
I have defined a class isActive in my css and that is applied/removed to the button on click. There are 5 results so 5 divs are created cause of ng-repeat and 5 buttons(1 for each respective div). The problem is that every button (all 5 of them) is getting that class. I want the class to be applied/removed only to the button clicked. How can I achieve this?
You can try something like this :
<div ng-controller="myTest">
<div ng-repeat="name in names">
<h4>{{name.name}}</h4>
<button ng-class="{ active : name.isActive }"
ng-click="name.isActive = !name.isActive">me</button>
</div>
</div>
Hope this will help.
You need to keep track of each button status.
One way will be to passing the name or anything that uniquely identify the button to your function:
<div ng-controller = "myTest">
<div ng-repeat="name in names">
<h4>{{name.name}}</h4>
<button ng-class="{'active': buttons[name].isActive}" ng-click="test(name)" >me</button>
</div>
</div>
$scope.buttons = {};
$scope.test= function(name){
$scope.buttons[name].isActive = !$scope.buttons[name].isActive;
}
I created a plunk that answers this question without modifying your source array.
Your function becomes
vm.test = function(buttonIndex) {
//Clear the class if you press the same button again
if (vm.buttonIndex === buttonIndex) {
vm.buttonIndex = undefined;
} else {
vm.buttonIndex = buttonIndex;
}
};
And your HTML is
<div ng-repeat="name in main.names track by $index">
<h4>{{name.name}}</h4>
<button ng-class="{'active': main.buttonIndex===$index}" ng-click="main.test($index)">me</button>
</div>

ng-click to affect only the element it is inside

I am using ng-repeat to generate some elements...
<div class="form-block" ng-repeat="form in formblock | filter:dateFilter">
<div ng-click="showResults()" ng-if="repeat == true" class="drop">{{ form.form_name }} <span class="caret"></span></div>
<div ng-show="results" class="formURL">{{ form.url }}</div>
<div ng-show="results" class="formCount">{{ form.count }}</div>
<div ng-show="results" class="formSubmit">{{ form.submit }}</div>
</div>
As you can see, ng-click="showResults()" toggles the display of the other elements. The problem is, I only want the ng-click to toggle the elements inside the same container, not toggle all elements.
In short, I only want the click event to affect the elements in the same container that the function is called, how can I do this?
this is showResults in my controller...
$scope.showResults = function(){
return ($scope.results ? $scope.results=false : $scope.results=true)
}
ng-repeat provides you with a special variable (unless you already have an identfier): $index.
Using this, you can store (instead of a single boolean value) an object $index => toggleState in your angular code:
$scope.hiddenHeroes = {};
$scope.toggleHero = function (idx) {
$scope.hiddenHeroes[idx] = !$scope.hiddenHeroes[idx];
}
And in your HTML:
<div ng-repeat="hero in heroes">
<div class="hero" ng-hide="hiddenHeroes[$index]">
<h1>
{{hero}}
</h1>
All you want to know about {{hero}}!
<br />
</div>
<a ng-click="toggleHero($index)">Toggle {{hero}}</a>
</div>
See it live on jsfiddle.net!
You can use $index to index item/containers and show the corresponding results:
<div ng-click="showResults($index)" ng-if="repeat == true" class="drop">{{ form.form_name }} <span class="caret"></span></div>
<div ng-show="results[$index]" class="formURL">{{ form.url }}</div>
<div ng-show="results[$index]" class="formCount">{{ form.count }}</div>
<div ng-show="results[$index]" class="formSubmit">{{ form.submit }}</div>
And your function
$scope.showResults = function(index){
return ($scope.results[index] ? $scope.results[index]=false : $scope.results[index]=true)
}

Angular Js ng-init is not working properly inside ng-repeat while setting a variable

I have a ng-repeat where i am checking a if condition and at the end of each repeation of loop i am setting a variable to a value from ng-repeat
Here is my variable which i want to set inside the ng-repeat
$scope.prvSid = "";
Here is my ng-repeat code
<ul class="chats" ng-repeat="chatData in chatboxData">
<li ng-class="{ 'out': chatData.sender_id == user_id , 'in': chatData.sender_id != user_id }">
{{ prvSid }}
{{ chatData.sender_id }}
<span ng-if=" prvSid != chatData.sender_id ">
<img class="avatar" alt="" src="{{ url('default/img/user_default_logo.jpg') }}" />
</span>
<div class="message">
<span class="body"> {{ chatData.message }} </span>
</div>
<span ng-init="prvSid = chatData.sender_id"></span>
{{ prvSid }}
</li>
</ul>
The problem which i am facing here is that whenever i print these values inside the ng-repeat then prvSid and chatData.sender_id is printing the same id the value of chatData.sender_id even for the first iteration and that's why this
<span ng-if=" prvSid != chatData.sender_id ">
condition is not working and my image is not displaying because for the first iteration the condition should be true because prvSid is "" and chatData.sender_id has some id in it
The purpose of this is to
Henry Zou the purpose is to not show profile picture for two or more messages submitted by same user (if the sender_id is same)Then dont display the profile image.When the new message comes from another sender which means sender_id is different then show the profile image
at first the prvSid will be null so it will show the image because condition will not match at the end of each iteration i will set the prvSid to the current iteration sender_id to match this prv_id with sender_id in the next iteration
i am also getting messages after two seconds and then i am adding the new records in the chatboxdata if they dont exist in it
$scope.getlasttwosecMsgs = function(user_id_chat,chat_id,user,chatboxData,is_new) {
$http.get(url+'/getlasttwosecMsgs/'+chat_id).success(function(data){
angular.forEach(data, function(value, key) {
var exists = $scope.containsObject(value,chatboxData);
if (!exists) {
$scope.chatboxData.push(value);
console.log($scope.chatboxData);
};
});
});
}
$scope.containsObject = function(obj, list) {
var i;
for (i = 0; i < list.length; i++) {
if (angular.equals(list[i], obj)) {
return true;
}
}
return false;
};
This new code snippet will check current userID against a list of users in the chatbox. For all users that's not the current user, show content.
approach #1 (preferred)
angular
.module('app', [])
.controller('myCtrl', function(){
var vm = this;
var prvSid = null;
vm.chatboxData = [{id:1},{id:1},{id:2},{id:3}];
vm.chatboxData.forEach(function(chatbox){
if(prvSid !== chatbox.id){
chatbox.showIcon = true;
}
prvSid = chatbox.id;
});
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<div ng-app="app">
<div ng-controller="myCtrl as vm">
<ul class="chats" ng-repeat="chatData in vm.chatboxData">
<li>
<span ng-if="chatData.showIcon ">
ICON
</span>
{{::chatData.id}}
</li>
</ul>
</div>
</div>
approach #2
angular
.module('app', [])
.controller('myCtrl', function(){
var vm = this;
vm.prvSid = null;
vm.chatboxData = [{id:1},{id:1},{id:2},{id:3}];
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<div ng-app="app">
<div ng-controller="myCtrl as vm">
<ul class="chats" ng-repeat="chatData in vm.chatboxData">
<li>
<span ng-if="chatData.showIcon ">
ICON
</span>
{{::vm.prvSid}} {{::chatData.id}}
<span ng-init="chatData.showIcon = (vm.prvSid !== chatData.id)"></span>
<span ng-init=" vm.prvSid = chatData.id"></span>
</li>
</ul>
</div>
</div>
approach #3 (without using controllerAs syntax)
angular
.module('app', [])
.controller('myCtrl', function($scope){
var prvSid = null;
$scope.chatboxData = [{id:1},{id:1},{id:2},{id:3}];
$scope.chatboxData.forEach(function(chatbox){
if(prvSid !== chatbox.id){
chatbox.showIcon = true;
}
prvSid = chatbox.id;
});
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<div ng-app="app">
<div ng-controller="myCtrl">
<ul class="chats" ng-repeat="chatData in chatboxData">
<li>
<span ng-if="chatData.showIcon ">
ICON
</span>
{{::chatData.id}}
</li>
</ul>
</div>
</div>
OLD ANSWER
In the video AngularJS MTV Meetup: Best Practices (2012/12/11), Miško
explains "..if you use ng-model there has to be a dot somewhere. If
you don't have a dot, you're doing it
wrong.."
ng-repeat creates an inherited scope (think javascript prototype) for each item.
This code below will create $scope.prvSid for each item in the array and the value will always be chatData.sender_id.
<span ng-init="prvSid = chatData.sender_id"></span>
If you meant it to only have 1 instances of prvSid id, then what you'll need to do is initialize prvSid variable at the parent scope first (or use the dot(.) rule)
<div ng-init="prvSid = null"> <!-- initializing prvSid id # parent scope -->
<ul class="chats" ng-repeat="chatData in chatboxData">
<li ng-class="{ 'out': chatData.sender_id == user_id , 'in': chatData.sender_id != user_id }">
{{ prvSid }}
{{ chatData.sender_id }}
<span ng-if=" prvSid != chatData.sender_id ">
<img class="avatar" alt="" src="{{ url('default/img/user_default_logo.jpg') }}" />
</span>
<div class="message">
<span class="body"> {{ chatData.message }} </span>
</div>
<!-- this will now update the parent scope's prvSid instead of creating a new one for each item in the array -->
<span ng-init="prvSid = chatData.sender_id"></span>
{{ prvSid }}
</li>
</ul>
</div>

My angular controller is not working?

I m new in Anguar js .
I have created a controller and pass the data but my controller not working can u please help me .
My code is this
Angular code is
var app = angular.module('myApp', []);
app.controller('myController', function($scope) {
$scope.person=[
{name:"Raj", gender:"M"},
{name: "raja", gender:"M"},
{name:"sevitra" gender:"F"}
]
});
HTML
Code is
<body ng-app="myApp">
<div controller="myController">
<a href="javascript:void()">
<button>Add New Field</button>
</a>
<div class="advance-menu-wraper">
<ul>
<li>
{{"person[0].name"}} + {{"person[0].gender"}}
<div class="head-text">Field 1:</div>
<div class="description-text">
How many staff members are proficient in Oracla programing
</div>
</li>
<li>
<div class="head-text">Field 2:</div>
<div class="description-text">
<form name="addForm">
<textarea rows="2"></textarea>
<div class="send-btn">
<button>
<i class="fa fa-check">Submit</i>
</button>
</div>
</form>
</div>
</li>
</ul>
</div>
</div>
</body>
Demo link
Your expression won't work:
{{"person[0].name"}} + {{"person[0].gender"}}
yields: "{{"person[0].name"}} + {{"person[0].gender"}}" in your html.
The correct expression would be:
{{person[0].name + person[0].gender}}
Moreover you have an syntax error in your array. The last object misses a comma.
This is a working plunkr: http://plnkr.co/edit/R9ojp8TWd7AloRrlPlZh?p=preview
You need to use the ngController directive
change
<div controller="myController">
to
<div ng-controller="myController">
{name:"sevitra" gender:"F"} should be {name:"sevitra", gender:"F"}
controller="myController" should be ng-controller="myController"
{{"person[0].name"}} + {{"person[0].gender"}} should be {{person[0].name}} + {{person[0].gender}}
three things which need to be change that i can see
change the controller to
app.controller('myController', [ '$scope',function($scope) {
change the <div controller="MyController"> to <div ng-controller="MyController"
and in the {{ " Person[0].Name "}} and {{ " Person[0].gender "}} remove the quote marks so it becomes {{Person[0].Name}} and {{Person[]0.gender}}

Why does my View not update in Angularjs on click, though I am able to get the content?

<div class="test" ng-controller="Ctrl">
<div ng-repeat="task in tasks">
<button ng-click="removeTask(task.id);">remove</button>
<div class="content">{{taskId}}</div>
</div>
<div>
var app = angular.module('app', []);
function Ctrl($scope) {
$scope.tasks = [{id:1,'name':'test1'}, {id:2,'name':'test2'}, {id:3,'name':'test3'}];
$scope.removeTask = function(taskId){
alert("Task Id is "+taskId);
};
}
The content I get in alert needs to be put in div, but the div won't get updated, what am I not doing correctly?
jsFiddle Demo
If you want id of task - task.id. taskId is just name for function parameter, it's undefined outside this function.
<div class="content">{{task.id}}</div>
But I suppose, best practice would be to pass whole object to click function:
$scope.removeTask = function(task){
alert("Task Id is " + task.id);
};
http://jsfiddle.net/PSz7t/3/
There different way's how you can achieve what are you looking for.
Here is mine. Since you need write an 'alert' for each removed item you need to save the status for each item so you can decide to show the alert or not
<div class="test" ng-controller="Ctrl">
<div ng-repeat="task in tasks">
<button ng-click="removeTask(task);">remove</button>
<div class="content"> <span ng-show="task.status=='deleted'">Task Id is {{task.id}} </span> </div>
</div>
<div>
http://jsfiddle.net/PSz7t/9/
var app = angular.module('app', []);
function Ctrl($scope) {
$scope.tasks = [{id:1,'name':'test1',status:'active'}, {id:2,'name':'test2',status:'active'}, {id:3,'name':'test3',status:'active'}];
$scope.removeTask = function(task){
task.status='deleted';
};
}

Categories

Resources