A simple application of todo not adding input value to view - javascript

Every time my controller adds new input on view but blank, I want it should add new input with entered value.
<div class="container">
<h2>My todos</h2>
<form ng-submit="addTodo()" role="form">
<input type="text" ng-model="todo" value="Something" placeholder="Add">
<input type="submit" value="Add">
</form>
<p class="form-group" ng-repeat="todo in todos">
<input type="text" ng-model="todo" class="form-control">
</p>
</div>
The above code has separate temple main.html and calling that code inside index.html
<div ng-include="'views/main.html'" ng-controller="MainCtrl"></div>
then whenever I add new todo, its add input blank, and add null value inside todos array list.
but when loading template without using ng-include its work fine.
angular.module('mymailApp')
.controller('MainCtrl', ['$scope', function ($scope) {
$scope.todos = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];
$scope.addTodo = function(){
$scope.todos.push($scope.todo);
$scope.todo = "";
};
}]);

Change "onDomReady" to "no wrap - in head" in the left panel "Frameworks & Extensions" panel
Also, in your module call, you want to pass a second parameter, an array containing all of your module's dependencies. In your case, an empty array []
angular.module('mymailApp',[]).controller(...)
Without the second parameter, it assumes you are trying to extend an existing module, not define a new one.
Updated your fiddle: http://jsfiddle.net/z2bvx2oh/11/

so i solved the issue moving controller call to "main.html" template, as ng-include template doesnt call the ng-controller directly, it should use either $routeProvider or controller should be call inside the template
modified code looks something like that:
ng-controller="MainCtrl" moves inside main.html

Related

AngularJS: ng-if outside ng-repeat breaks ng-repeat

AngularJS Verion: 1.3.8
JSFiddle: http://jsfiddle.net/uYFE9/4/
I've been working on a small AngularJS application, and ran into a bit of a problem. I have an ng-repeat on a page, which fills in the contents of a form. The amount of items in the form is defined by a dropdown bound to a model, and populated using ng-options. Something like:
<select id="testAmount" ng-model="selectedItem" ng-options="item.name for item in items"></select>
<form role="form" name="testForm" ng-if="!complete">
<div ng-repeat="i in getNumber(selectedItem.number) track by $index">
{{$index}}
</div>
</form>
Complete is set to false in the beginning, and hitting a Next button will toggle complete and hide the form and dropdown. A Back button will then toggle complete back, and show the form again.
The problem I'm having is with the ng-if on the select (and previously, I had the form wrapped in a div with the same ng-if - same problem). The ng-repeat no longer updates when the select dropdown is changed. Removing the ng-if on the select restores the ng-repeat to working order.
I'm wondering if there's something strange I'm doing with the nesting here, or if it's actually a bug? You can test it out on the JSFiddle linked above. The $index should be printed the number of times on the dropdown, but isn't.
Interestingly enough - when debugging the problem on my local machine, having FireBug open fixed the issue.
This is because of ng-if creating a child scope and how prototypical inheritance works with primitives. In this case, the primitive is selectedItem that you are setting by the <select>, but is actually being set on the child scope and shadows/hides the parent scope property.
In general you should always use a dot (.) with ng-models:
$scope.selection = {selectedItem: undefined};
And in the View:
<div ng-if="!complete">
<select ng-model="selection.selectedItem"
ng-options="item.name for item in items"></select>
</div>
ng-if is causing you some scoping issues (which messes with the binding).
Here is an updated jsfiddle that you could use as a work around. Essentially, this example wraps another div around the items that you want to end up hiding. And then adds a next function so that the same scope is affected during the click that sets complete to true.
HTML:
<div ng-app="test">
<div ng-controller="TestCtrl">
<div ng-if="!complete">
<div>
<label for="testAmount">Amount:</label>
<select id="testAmount" ng-model="selectedItem" ng-options="item.name for item in items"></select>
</div>
<form role="form" name="testForm">
<div ng-repeat="i in getNumber(selectedItem.number) track by $index">
{{$index + 'hi'}}
</div>
<button class="btn btn-default" value="Next" title="Next" ng-click="next()">Next</button>
</form>
</div>
<div ng-if="complete">
</div>
</div>
</div>
JS:
angular.module('test', [])
.controller('TestCtrl', function($scope) {
$scope.complete = false;
$scope.items = [
{ name: '2', number: 2 },
{ name: '3', number: 3 },
{ name: '4', number: 4 }
];
$scope.selectedItem = $scope.items[0];
$scope.getNumber = function (number) {
return new Array(number);
};
$scope.next = function() {
$scope.complete = true;
};
})
I believe the problem is with your select statement inside an ng-if the selectedItem is never getting set. If you just don't want to show that dropdown when !complete change it to an ng-show and it works fine.
<div ng-show="!complete">
As to WHY the ng-model is not being bound inside the ng-if, I don't really know but it does make some sense in that you are trying to do a conditional bind which is a bit screwy

AngularJS ng-model $scope in ng-repeat is undefined if update from outside ng-repeat $scope is also undefined

I was looking this example AngularJS ng-model $scope in ng-repeat is undefined in this question first answered by #Gloopy here http://jsfiddle.net/VnQqH/128/
My question is can I update ng-model values in ng-repeat scope from outside of ng-repeat scope like this:
<div ng-app="MyApp">
<div ng-controller="PostCtrl">
<div ng-repeat="post in posts">
<strong>{{post}}</strong>
<input type="text" ng-model="postText">
</div>
/*Update ng-model values (in ng-repeat scope) using single click*/
save post
</div>
</div>
Here is controller:
angular.module('MyApp',[]);
function PostCtrl($scope) {
$scope.posts = ['tech', 'news', 'sports', 'health'];
$scope.savePost = function(post){
alert( 'post stuff in textbox: ' + post);
}
}
I tried but got undefined :( My experimental fiddle is here http://jsfiddle.net/hot81o2z/ If anyone has the solution for this problem please share. Many thanks in advance.
You can make use of $parent in order to pass a scope variable outside of the ng-repeat directive, something like this
HTML:
<div ng-app="MyApp">
<div ng-controller="PostCtrl">
<div ng-repeat="post in posts">
<strong>{{post}}</strong>
<input type="text" ng-model="$parent.postText">
</div>
<!--Update on single click-->
save post
</div>
</div>
Controller: Not changed anything, kept what you had
Working Demo

How do I set the value of element in Angular.js

Why can't I do this in Angular.js:
document.getElementById('divid').value = 'Change Text to This';
And what is the "right" (Angular) way of doing it?
In Angular you use the ng-model directive in order to create a two-way data binding between your model (i.e. a JS variable) and the view (i.e. the <div>). Basically, this means that whenever you change the data in the view (through an input, for instance), the change will be reflected in your JS variable. See below:
HTML:
<html ng-app="myApp">
<div ng-controller="MyCtrl">
<div>{{myVariable}}</div>
<input type="text" ng-model="myVariable" />
</div>
</html>
JS:
/* App global module */
var myApp = angular.module('myApp');
/* Define controller to process data from your view */
myApp.controller('MyCtrl', function($scope) {
$scope.myVariable = "initialValue"; // this is the variable that corresponds to text inserted in your input
});
Here, myVariable will have "initialValue" as an initial value. Any further changes to the input will overwrite the value of this variable.
Also notice that {{myVariable}} injects the variable the data into your div. When you change the value in the input, the div text will be changed as well.
You'd have to bind a controller to your mark up and initialise your Angular app.
<div ng-app="myApp">
<div id="divid" ng-controller="valueController">{{value}}</div>
</div>
Then you can simply define a scope variable in your controller
myApp.controller("valueController", function($scope) {
$scope.value = "Hi!";
});
It is considered best to use the ng-app directive in the HTML tag of the page
jsFiddle

Angular JS $scope query

I'm trying to do the following:
Type something in a search box, perform the related search and show the result defined in a separate view template.
The search thingy is part of a page header and so, my index page is as follows:
index.html
<div class="row search-box">
<div class="col-md-2"></div>
<div class="col-md-6">
<form id="myForm" class="form-inline form-search"
style="padding-left: 10px">
<!-- Search box -->
<input id="in" type="text" ng-model="searchTerm" placeholder="Search for products, categories or brands"
class="search-query input-search">
<button class="btn searchBtn" ng-click="doSearch()" ng-controller="MediaListController">
<i class="icon-search"></i>Search
</button>
</form>
</div>
<div class="col-md-3">
<div class="btn btn-blue cart-btn-cont">
<span class="cart-icon"></span>
</div>
</div>
</div>
...
<div ng-view></div>
Controller (relevant function)
$scope.doSearch = function () {
var type = $scope.mediaType;
$scope.foundItems = MediaService.search().length;
console.log("Found items :"+ $scope.foundItems + "for search term :"+ $scope.searchTerm);
$location.path("/search");
}
app.js
var app= angular.module('sampleApp', ['ngRoute','ngResource','mgcrea.ngStrap']);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/login', {templateUrl: 'app/views/partials/login.html', controller: 'LoginController'});
$routeProvider.when('/search', {templateUrl : 'app/views/partials/tpl/search_result.tpl.html'});
$routeProvider.when('/', {templateUrl: 'app/views/landing_page.html', controller: 'MediaListController'});
$routeProvider.otherwise({redirectTo: '/'});
}]);
Search result template:
Found {{ foundItems }} product(s) for search phrase <i>"{{searchTerm}}"</i>
It all works fine, but in getting to this stage, I am confused by the following:
a. Why is $scope.foundItems not visible in the template i.e, {{foundItems}} works only when I use $scope.$parent.foundItems in the controller?
b. If a new child scope is being created, how come $scope.searchTerm is available in the view template i.e., {{searchTerm}}? Is it because ng-model="searchTerm" creates a model binding in the rootScope?
c. I also saw that {{foundItems}} in the template worked fine if I used $rootScope.foundItems, but what if I want to avoid $rootScope - is the use of $scope.$parent valid?
Thanks in advance.
a. Why is $scope.foundItems not visible in the template i.e, {{foundItems}} works only when I use $scope.$parent.foundItems in the controller?
I think it's a little strange to assign the same controller in the ng-view and then another tag like button. Because button will create its own scope right there. And then ng-view also creates one.
b. If a new child scope is being created, how come $scope.searchTerm is available in the view template i.e., {{searchTerm}}? Is it because ng-model="searchTerm" creates a model binding in the rootScope?
that scope has nothing to do with the doSearch scope actually.
c. I also saw that {{foundItems}} in the template worked fine if I used $rootScope.foundItems, but what if I want to avoid $rootScope - is the use of $scope.$parent valid?
You should probably have a main controller for the page and then call everything from there perhaps.

Scope problems in basic Yeoman Angular Todo App

I'm following the tutorial here: http://www.youtube.com/watch?v=iUQ1fvdO9GY while learning yeoman and angular.
I've gotten to here http://www.youtube.com/watch?v=iUQ1fvdO9GY#t=266 and where his example works, mine does not due to some scope problems.
main.html
<div class="jumbotron">
<h2>My Todos:</h2>
<p ng-repeat="todo in todos">
<input type="checkbox" ng-model="todo.done">
<span>{{todo.text}}</span>
</p>
<form ng-submit="addTodo()">
<input type="text" ng-model="newTodoText" size="20">
<input type="submit" class="btn btn-primary" value="add">
</form>
</div>
main.js
'use strict';
var myApp = angular.module('todoAppApp');
myApp.controller('MainCtrl', ['$scope', function ($scope) {
$scope.todos = [
{text: 'Item 1', done: false},
{text: 'Item 2', done: true},
{text: 'Item 3', done: false}
];
$scope.addTodo = function() {
$scope.todos.push({text: $scope.newTodoText, done: false});
$scope.newTodoText = '';
};
}]);
For some reason, though, the newTodoText variable is in a scope that is child to the $scope in main.js. This is confirmed using Batarang. I can't post a picture due to lack of rep, but in Batarang, there's:
Scope001 > Scope002 > Scope003(which is the $scope I have access to in the js) > Scope004 > {Scopes for each of the todos}
Scope003 has the original todos array and the addTodo() function. Scope004 has the newTodoText text when you type into the input form. On clicking add, addTodo() is correctly called, but $scope doesn't contain newTodoText because it's in Scope004.
I'm obviously missing something simple here due to my newness to the framework and the practically barebones implementation here. My Google-fu has turned up few results.
EDIT:
Ok, so in index.html, it contains the line
<div class="container" ng-include="'views/main.html'" ng-controller="MainCtrl"></div>
which includes main.html. I've replaced that line with the literal contents of main.html enclosed in the div
<div class="container" ng-controller="MainCtrl">
<!-- contents of main.html from above -->
</div>
And magically my scope problems are solved. Why does including main.html from a separate file mess with the scope?
EDIT #2
Cool, I figured it out.
Turns out that ng-include creates a new scope, which is contrary to what I thought it did (I had assumed that it was equivalent to a literal html injection). So I just moved the ng-controller="MainCtrl" from the .container div in index.html (Scope003) to the .jumbotron div within main.html.
Thanks for the help, and I'm a lot more knowledgeable about scope now!
ng-include creates a new scope. So I moved the ng-controller="MainCtrl" from the .container div in index.html (Scope003) to the .jumbotron div within main.html.

Categories