How to prepopulate ngModel in AngularJS - angularjs

I have no idea how to pre-populate an ng-model in this circumstance that I have to use ngBind. I tried ng-init, but it's not working.
<h6 ng-show="isOwner" ng-bind="currentMagazine.magazine_name"
contenteditable ng-model="currentMagazine.magazine_name"
ng-change="update()"></h6>
I have a seperate directive that binds contenteditable attributes to ngModelController.
The problem now is whenever I update the model, ng-bind will jump out and refresh the div element, resulting in the cursur going back to the beginning of the text, which makes it impossible for any user to type.
I tried ng-init in a fashion like this:
<div ng-init="magazineName = currentMagazine.magazine_name">
<h6 ng-show="isOwner"
contenteditable ng-model="magazineName"
ng-change="update()"></h6>
</div>
It's not working. If I don't use ng-bind, then no text will show up.
Also I notice it might be related to this problem, when I type with space or delete key, they are escaped into HTML entities...so you get result like this:
Hopefully both of my problems can be solved! Thank you (it's a very frustrating day)!

In your app.js do this:
$scope.magazineName = $scope.currentMagazine.magazine_name;
In your HTML do something like this:
<input
ng-show="isOwner"
contenteditable
ng-change="update()"/>
or
<h6 ng-show="isOwner"
contenteditable
ng-model="currentMagazine.magazine_name"
ng-change="update()">
{{currentMagazine.magazine_name}}
</h6>
... though perhaps not, it's a bit difficult to gauge without seeing it... please make a jsfiddle or plunkr if you'd like to get more eyes on it.
If you're just trying to make some large text that is still editable and bound to the model it may be easier to just style an input for your needs.
Decided to play with contenteditbale since it's chance for me to learn something too... I can't seem to recreate the issue though:
http://jsfiddle.net/VSJQX/
I saw after doing this it wasn't updating the model, found another SO post that resolves that and included the changes here:
http://jsfiddle.net/VSJQX/2/

Related

Angular radio button scope

I'm working on a radio button list where a user can select from a pre-populated list of problems, or select an "other" radio button and then type in their specific problem.
I can get the pre-populated list of radio buttons to work and set the problem (outputting the scope variable confirms this), but introducing the "other" functionality is stumping me. When I select other, it doesn't seem to bind to the scope variable. I noticed in the dom it's missing an class="ng-scope" that the other radio buttons seem to get from the ng-repeat, but I'm not sure if that's the problem.
<form>
// This part loops through the list of problems and makess radio buttons
<div ng-repeat="problem in selectedType['nature_of_problem']">
<input type="radio" ng-model="$parent.natureOfProblem" ng-value="problem"/>
</div>
// Ideally this part is where the "other" radio is, it's still in the form
<input type="radio" ng-model="natureOfProblem" ng-value="other" ng-checked="">
</form>
Working JSFiddle:
http://jsfiddle.net/HB7LU/3794/
I saw a few issues, among them:
Using ng-value instead of plain old value for "other"
Using a primitive instead of dot notation (if you want your view to reliably write a variable, it needs to be something.yourVariable instead of just plain old yourVariable)
Hope this helps!
function MyCtrl($scope) {
$scope.uiState = {};
$scope.uiState.natureOfProblem = 1;
$scope.selectedType = {};
$scope.selectedType.nature_of_problem = [1,2,3];
}
<div ng-controller="MyCtrl">
<p>Nature of problem is: {{uiState.natureOfProblem}}</p>
<form>
<div ng-repeat="problem in selectedType['nature_of_problem']">
<input type="radio" ng-model="uiState.natureOfProblem" ng-value="problem"/><span ng-bind="problem"></span>
</div>
<input type="radio" ng-model="uiState.natureOfProblem" value="Other" /><span>Other</span>
</form>
</div>
EDIT to answer OP's questions:
I tend to use ng-bind out of habit -- in slower browsers like Firefox, it keeps "{{blah}}" from showing up on the screen as everything loads. Newer versions of Angular also have ng-cloak for this purpose, which I should probably get in the habit of using instead. :) (I also vaguely remember reading that "{{blah}}" can cause issues in IE, but I very possibly made that up.)
The use of dot notation relates to the fact that Angular can't maintain data bindings on brand-new objects. To try to explain it without using terms like "scope" and "inheritance": If you influence an existing object by changing yourObject.anAttribute, the overarching object consistently exists throughout that process and does not drop its binding. But if you have blahVariable that is equal to 8, and you set blahVariable equal to 7, you've basically tossed the old piece of data and created a new piece of data entirely. This new piece does not maintain the binding, so the controller never gets the memo from the view that the value has changed.
Sometimes I find this useful, actually -- you can briefly manipulate a variable in the view for some quick-and-dirty purpose without the controller finding out about it. :)

Include behaviour inside ng-switch

I'm building a reasonably non-trivial Angular-js application for the first time and am trying to establish some intuition about how to get things done. Most things are making sense, but there's one pattern in particular that has me stumped -
Whenever I place an "include" style directive inside an ng-switch, it is ignored. I've experimented with just about every style of ng-switch, ng-include, and ng-transclude I can think of to achieve the desired behaviour, but to no avail. I haven't noticed any documentation indicating that this would be disallowed, nor any equivalent style of pattern.
Here is an example of what I have tried to do:
<div ng-switch="is_logged_in()">
<div ng-switch-when="true">
logged-in:
<div ng-include="'views/logout.html'"> </div>
</div>
<div ng-switch-default>
not-logged-in
</div>
</div>
The expected behaviour being that the logout form is displayed when $scope.is_logged_in() returns true.
The behaviour I see is that "logged-in:" is displayed, but the include isn't.
I've tried various versions of Angular-js. I've inspected the network traffic and seen that the include is in-fact being fetched, but I can't get this to work. I've had the same behaviour manifest when trying to build my own template control structures using directives.
The way I've seen most examples dodge this is by using JS in a directive to manually show/hide various sections of the transcluded content - is this really the idiomatic way to get the behaviour I'm looking for?
Thanks!
While using ng-include I always assign the path to a variable in controller.
$scope.logoutlink ='views/logout.html'
And in the view you can assign as
<div ng-include="{{logoutlink}}"> </div>
It would be helpful to post a JSfiddle link.

ngRepeat breaks the Foundation Switch CSS. How can I fix it?

I'm trying to use the Switch component from Zurb's Foundation.
It works great until you put it inside an ng-repeat. Then, all the switches except the last one are broken--they don't display the labels until you click them.
Here's a JSBin documenting the issue. Anyone know what's up?
You need ng-model on your radios. It works fine in your JSBin if you include an ng-model on each radio button.
According to the docs, value is also required.
Edit:
Okay look at this version, I finally got it to work with both ng-model and ng-value, which I've learned is preferable to value. What do you think, does that work for you?
Apparently ng-repeat created a child scope for each iteration. Using $parent seems to be a way around that.
Found I had to use "ng-checked" in the following fashion for it to work as expected within an "ng-repeat". As long as the ng-clicked var is unique per switch, should work as expected. Make the toggle function something that toggles the visible value between true and false.
<div class="switch" ng-click="toggle()">
<input type="radio" ng-checked="!visible">
<label>Off</label>
<input type="radio" ng-checked="visible">
<label>On</label>
<span></span>
</div>
Hope that helps someone.

Is there a way to make AngularJS work with HTML-first?

Is there a way to have a HTML-view with pre-populated values from the server, and then get AngularJS to read those values into it's $scope?
I'm thinking of a scenario where the HTML is like this:
<div ng-controller="TestController">
<div ng-bind="title">Test Title</div>
<div ng-bind="itemCount">33</div>
<div ng-repeat="item in items">
<div ng-bind="item.title">Item 1 Title</div>
</div>
</div>
<button ng-click="update()">Update</button>
And the JavaScript is like this:
function TestController($scope) {
$scope.update = function() {
console.log($scope.title); // Should log "Test Title"
};
}
The thought behind this is to let the server render HTML that search engines can index, but have a JavaScript-model-representation of the content for manipulation through JS.
While ng-init is one solution, it requires you to explicitly set the value. So here is an alternative solution.
http://plnkr.co/edit/pq8yR9zVOHFI6IRU3Pvn?p=preview
Note : This solution wont work for ng-repeat. Control flow directives cant be used with this. But for simple extraction of information from ng-bind this works pretty well. All that you need to do is add the default directive ( code in plunk ) to wherever you are doing the bind and it will extract the text content and push it to the scope variable.
EDIT (solution with ng-repeat):
So, I was thinking of a way to make ng-repeat also work the same way. But getting ng-repeat to work like this isnt an easy job ( see the code for proof :P ). I have finally found a solution - here you go :
http://plnkr.co/edit/GEWhCNVMeNVaq9JA2Xm2?p=preview
There are a couple of things you need to know before you use this. This hasnt been thoroughly tested. It only works for repeating over arrays ( not objects ). There could be cases that have not been covered. I am overriding ngRepeat itself which could have other consequences. When you loop through the items ( in your server side code ) dont forget to add default="true" on the first element and default on the rest of the elements.
Hope this helps.
Add ng-init to your elements with the value so that it will work the way you want.
http://docs.angularjs.org/api/ng.directive:ngInit
I think what you really want is to make your application searchable by serving static files in parallell. Read more about it here http://www.yearofmoo.com/2012/11/angularjs-and-seo.html

Dynamic data-binding in AngularJS

I'm building an AngularJS app and I have ran into an issue. I have been playing with the framework for a while and I have yet to see documentation for something like this or any examples. I'm not sure which path to go down, Directive, Module, or something that I haven't heard of yet...
Problem:
Basically my app allows the user to add objects, we will say spans for this example, that have certain attribute's that are editable: height and an associated label. Rather than every span have its own dedicated input fields for height and label manipulation I would like to use one set of input fields that are able to control all iterations of our span object.
So my approx. working code is something like this:
<span ng-repeat="widget in chart.object">
<label>{{widget.label}}</label>
<span id="obj-js" class="obj" style="height:{{widget.amt}}px"></span>
</span>
<button ng-click="addObject()" class="add">ADD</button>
<input type="text" class="builder-input" ng-model="chart.object[0]['label']"/>
<input type="range" class="slider" ng-model="chart.object[0]['amt']"/>
The above code will let users add new objects, but the UI is obviously hardcoded to the first object in the array.
Desired Functionality:
When a user clicks on an object it updates the value of the input's ng-model to bind to the object clicked. So if "object_2" is clicked the input's ng-model updates to sync with the object_2's value. If the user clicks on "object_4" it updates the input's ng-model, you get the idea. Smart UI, essentially.
I've thought about writing a directive attribute called "sync" that could push the ng-model status to the bound UI. I've though about completely creating a new tag called <object> and construct these in the controller. And I've thought about using ng-click="someFn()" that updates the input fields. All of these are 'possibilities' that have their own pros and cons, but I thought before I either spin out on something or go down the wrong road I would ask the community.
Has anyone done this before (if so, examples)? If not, what would be the cleanest, AngularJS way to perform this? Cheers.
I don't think you need to use a custom directive specifically for this situation - although that may be helpful in your app once your controls are more involved.
Take as look at this possible solution, with a bit of formatting added:
http://jsfiddle.net/tLfYt/
I think the simplest way to solve this requires:
- Store 'selected' index in scope
- Bind ng-click to each repeated span, and use this to update the index.
From there, you can do exactly as you proposed: update the model on your inputs. This way of declarative thinking is something I love about Angular - your application can flow the way you would logically think about the problem.
In your controller:
$scope.selectedObjectIndex = null;
$scope.selectObject = function($index) {
$scope.selectedObjectIndex = $index;
}
In your ng-repeat:
<span ng-repeat="widget in chart.object" ng-click="selectObject($index)">
Your inputs:
<input type="text" class="builder-input" ng-model="chart.object[selectedObjectIndex]['label']"/>
<input type="range" class="slider" ng-model="chart.object[selectedObjectIndex]['amt']"/>

Resources