Observables in Angularjs - javascript

I'm doing few exercises to understand how Angularjs work... but I'm a bit confused at the moment...
Following the API, various documentation and tutorials I cannot find exactly what I would like to see...
So I created a small JsFiddle: http://jsfiddle.net/8HqnZ/
What I'm doing is really basic... and probably I'm also doing in a bad way... but I'm learning and every tips will be fantastic for me.
My target here is:
Make everything dynamic... obviously.
I don't understand why if I change name or date on my inputs on top my red bars do not update (seems like it isn't observable...)
I also created a get data button to see my updated Json but it return just [object, Object]...
In plus after I understand these two things I would like to make it inverse as well... I mean something like a draggable red bars that will update date on top... (if it is possible).
Here is my small app:
function App($scope) {
$scope.windows = [
{"name":"First Window","from":"2013-11-05","to":"2013-11-21"},
{"name":"Second","from":"2013-11-10","to":"2013-11-30"},
{"name":"Another One","from":"2013-11-17","to":"2013-11-20"}
];
$scope.addWindow = function() {
$scope.windows.push({"name":"insert name","from":"2013-11-01","to":"2013-11-02"});
};
$scope.setWindow = function(from, to) {
var f = (from.split("-")[2]) * 40,
t = ((to.split("-")[2]) * 40) - f;
return { f: f, t: t };
};
$scope.getData = function() {
console.log($scope.windows);
};
};
The HTML looks like this (I cutted off the "calendar"):
<div ng-app ng-controller="App">
<section id="window-data">
<div ng-repeat="window in windows">
<label>Name:<input value="{{window.name}}"></label> <label>From:<input type="date" value="{{window.from}}"></label> <label>To:<input type="date" value="{{window.to}}"></label>
</div>
<button id="add-window" ng-click="addWindow()">Add Window</button>
</section>
<section id="window-display">
<div id="date-labels">
<div class="block">
<span class="rotate">2013-11-01</span>
</div>
<div class="block">
<span class="rotate">2013-11-02</span>
</div>
...
</div>
<div id="windows">
<div class="window-container" ng-repeat="window in windows">
<span class="window" style="left:{{setWindow(window.from, window.to).f}}px; width:{{setWindow(window.from, window.to).t}}px">{{window.name}}</span>
</div>
</div>
</section>
<button id="get-data" ng-click="getData()">Get Data</button>
</div>
Please if you know good websites with easy and deep documentation, examples, etc... share it with me.

I've always just used the Angular site for documentation. Have you gone through their tutorial?
For your issues: You'll want to use ng-model on those inputs instead of setting the value.
<input ng-model="window.name">
The other issue occurred because you are trying to console.log JSON. You'll need to turn it into a string to log it:
console.log(JSON.stringify($scope.windows));
http://jsfiddle.net/8HqnZ/1/

1.
I don't understand why if I change name or date on my inputs on top
my red bars do not update (seems like it isn't observable...)
To do 2 way data binding you need to use ng-model
Specifically you need to do this
`<input ng-model="window.name">`
instead of input value as "window.name"
I also created a get data button to see my updated Json but it return
just [object, Object]...
This is as expected.
For a draggable, you need to create a custom angular js directive.

Related

How can we increment the Semantic UI Progress bar based on the mongoDB data?

I have a situation where the progress of a job should be displayed on the UI, for that I'm constantly(5 sec) retrieving the job progress and storing into mongoDB. As Semantic UI provide progress bar functionality, I tried implementing in my meteor project. The problem is that progress is not getting incremented.
sample.html
<div class="ui blue active progress stats" style="padding:0.25%;;width:7%;margin:0% 1%;margin-top:0.5%;" data-value={{prog}} id="statProgress">
<div class="bar">
<div class="progress {{progValue}}"></div>
</div>
</div>
sample.js
$('#statProgress')
.progress({
label: 'ratio',
text: {
ratio: '{value}'
}
});
Template.sample.onRendered (function(){
var progv=Session.get("selectedProgress");
this.$('.ui.progress').progress({value: progv});
});
Template.sample.helpers({
'progValue':function(){
var id=this._id; //job ID
console.log("inside the progValue and the id is: ",id);
var jobDetails=job.find({_id:id}).fetch();
console.log(jobDetails);
console.log(jobDetails[0].prog);
Session.set("selectedProgress",jobDetails[0].prog);
var x=Session.get("selectedProgress");
console.log(x);
}
});
Can anyone point where exactly I have missed out and how can i correct it?
Several things to double check:
Semantic UI initialisation: Your don't need to set a value here as your value will be provided by your helper
Template.sample.onRendered (function(){
var progv=Session.get("selectedProgress");
this.$('.ui.progress').progress();
});
Semantic UI usage (I removed your style for simplicity): If you use data-value to get the value of the Blaze helper, you don't need to add the value again in the inner div.
<div class="ui blue active progress stats" data-value={{progValue}} id="statProgress">
<div class="bar">
<div class="progress"></div>
</div>
</div>
Blaze Helper: Your helper should return a value ! If your last statement is a console.log(..), the return value will be 'undefined'. You don't need the Session as the Mongo find is also reactive and will re-run on every update (By the way, another suggestion could be to query your collection with 'findOne' instead of find().fetch() and your helper could take a single line):
'progValue':function(){
var id=this._id; //job ID
var jobDetails=job.find({_id:id}).fetch();
return(jobDetails[0].prog);
}
Good luck
JF

Add class on hover on Angular JS

I'm trying to add a class when hovering the li element in the code below with Angular
<li ng-mouseenter="cola-selected=true" class="pull-left" ng-class="{'selected' : cola-selected}">
<a href="interna.html">
<img src="assets/images/cola.png">
</a>
</li>
This is all the functionality the page will have, so I though maybe it is not necessarily to add a new js file for the js.
When the mouse enter to the li it should have the new class selected. The code above it is not working, and I cannot figure out why.
Here is an example of my code on a fiddle: https://jsfiddle.net/mjrmeffc/
Why do you need an extra file if you can write the logic in your angular application?
I assume you make use of ng-app and have a so called javascript file where your logic is, and you should include it in here.
Here is an example of the proper way of adding/removing a class.
<div ng-app>
<div
class="italic"
ng-class="{red: hover}"
ng-mouseenter="hover = true"
ng-mouseleave="hover = false">
Test 1 2 3.
</div>
</div>
NB I found this in another stackoverflow question, please make proper use of google search first, I don't have enough reputation to flag your question, or to make a comment.
* EDIT *
It seems like you're not yet familiar with AngularJS. You need to include your 'app.js' or 'script.js' whatever you want to call it. In there you define your application using
var app = angular.module('yourappname', [/* add your dependencies here*/]);
//Other logic like controllers or services
And your HTML should be
<div ng-app="yourappname">
<div ng-controller="yourController">
PLEASE ORIENTATE YOURSELF FIRST BEFORE YOU START ASKING QUESTIONS
Try using ng-mouseover attr
<li ng-mouseover="hoverIn()" class="pull-left" ng-class="{{applyClass}}">
write a function hoverIn() in your script and assign value when hover over
$scope.hoverIn = function() {
this.applyClass = "red";
}
Working Demo

Razor model helpers in jquery/handlebars infinite scroll

I'm using MVC5 and originally had a standard MVC implementation with manual paging and all was well. Except, when I showed it to my friend, he's like "What are all these number things down here?" (referring to the paging buttons, in his defense he was using his smart phone). It was then I decided infinite scroll would be much better.
After what seems like a million google searches, most the solutions (as well as ALL the solutions that I can actually understand) use json and jquery. Since I was using Troy Goode's PagedList already to do the manual paging, I went with his recommended solution here:
How Can I Convert My Paging Functionality To Use AJAX Insead?
And, I came up with this using json, jquery and handlebars:
<div id="incidentsList"></div>
<div id="incidentsWaypoint">.</div>
#section Scripts{
<script id="incident-template" type="text/x-handlebars-template">
<div class="tRoot">
<div class="tRow">
<div class="index-title">
{{Title}}
</div>
</div>
<div class="tRow">
<div class="index-description">
{{Description}}
</div>
</div>
<div class="tRow">
<div class="pCount">
Count: {{Count}}
</div>
<div class="pSend">
!!!!Partial View Here!!!!
</div>
</div>
</div>
</script>
<script type="text/javascript" src="/Scripts/handlebars-v3.0.3.js"></script>
<script type="text/javascript" src="/Scripts/waypoints.min.js"></script>
<script type="text/javascript">
var source = $("#incident-template").html();
var template = Handlebars.compile(source);
$(function () {
var page = 1;
var $incdiv = $('#incidentsList');
var $waypoint = $('#incidentsWaypoint');
var opts = { offset: '100%' };
$waypoint.waypoint(function () {
$waypoint.waypoint('remove');
$.getJSON('#Url.Action("AjaxPage", "Incidents")', { page: page++ }, function(incidents) {
$.each(incidents, function (index, incident) {
var pPartial = '#Html.Partial("_ProjectStatus", incident)';
//console.log(incident.Title);
//var context = { IncidentId: incident.IncidentId, Title: incident.Title, Description: incident.Description, Count: incident.Count };
var context = incident;
$incdiv.append(template(context));
});
$waypoint.waypoint(opts);
});
}, { offset: '100%' });
});
</script>
}
It works well as far as I can tell, except that I now seem to have lost the ability to use razor html helpers and such, more specifically that #Html.Partial("_ProjectStatus", incident) that has logic like:
if (!Model.IsOwner(Context.User.Identity.Name))
{
if (Model.IsSent(userId))
{
So, I can't just generate straight html for that...
I was going to chop the handlebars template up into smaller templates and then hopefully use the razor helpers in jquery like I started with the var pPartial and then append it all together in the jquery code, but wanted to post it here first before I do all the work to see if I'm even on the right track, especially since (after many more searches) I haven't really found anyone trying to do this.
Therefore, my question(s) is (and I wouldn't expect them all answered, I'm just not sure what to ask and hoping someone can see what I'm trying to accomplish), will what I'm trying to do in the previous paragraph even work? Are razor helpers/logic out of the question in handlebars templates? Are there examples somewhere?...especially of someone who has a full implementation (i.e. something a little more complex than just a list where the example actually uses helpers/logic in it)? Is there another way to do infinite scroll that would allow me to keep my razor code or solely use partial views (or similar) with minimal jquery maybe?
As always, I appreciate any guidance. Thank you.
So far, I fixed it by moving my view logic (learned from nerddinner...which also makes me think of another question) to the controller, by simply adding the last two lines to my json result and returning them as bools:
var incidents = listPaged.Select(items => new
{
items.IncidentId,
items.Title,
items.Description,
items.Count,
IsOwner = items.IsOwner(userName), // this one
IsSent = items.IsSent(userId) //and this one
});
Then in handlebars, I did:
{{#unless IsOwner}}
{{#if IsSent}}
<div class="sent">Sent...</div>
{{else}}
<div class="sent">Not Sent...</div>
{{/if}}
{{/unless}}
I tried to do the partial view with #Html.Action and a few other things that were really straining my mind how they could even possibly work. I like to keep things simple and the couple things I got to sort-of work were noticeably slower (~20%).
This fix is slightly faster too by about 10% on average. Maybe because I'm not pulling every field in the model now? Anyway, wish I could use those helpers in the template, but i can live with this, especially since it allows me to move on...
I'd love to hear any other opinions. Thanks.

Combining ngClick with ngSwitch

I know this is a scoping issue, but I can't seem to figure it out. I want to simply change one div into another one by pressing a button. In other words, ng-click will perform the necessary changes for ng-switch to activate.
However, my buttons are both nested within their respective ng-switch-when div so I'm assuming that is the problem.
Here is a fiddle of what I'm talking about: http://jsfiddle.net/gGKGX/8/
Thank you in advance!
In Angular, ng-switch creates a new scope, which means that variables set in a ng-switch constructs aren't accessible outside of it.
In your current scenario as you have defined thingToShow in controller use $parent.thingToShow like
<button ng-click="$parent.thingToShow='two'">Switch!</button>
DEMO
You could have ngClick call a function which updates the thingToShow on the scope.
http://jsfiddle.net/gGKGX/9/
JS:
angular.module("myApp",[]).controller("MainController", function($scope) {
$scope.thingToShow = "one";
$scope.showThing = function (thing) {
$scope.thingToShow = thing;
};
});
View:
<div ng-controller="MainController" ng-app="myApp">
<div ng-switch="thingToShow">
<div ng-switch-when="one">
Showing Thing One
<button ng-click="showThing('two')">Switch!</button>
</div>
<div ng-switch-when="two">
Showing Thing Two
<button ng-click="showThing('one')">Switch!</button>
</div>
</div>
</div>
In addition to the other answers you can use an object value (since things like strings aren't passed through the isolate scope set up by the switch) http://jsfiddle.net/gGKGX/14/
// dom
<div ng-switch="thingToShow.val">
<div ng-switch-when="one">
Showing Thing One
<button ng-click="thingToShow.val = 'two';">Switch!</button>
</div>
<div ng-switch-when="two">
Showing Thing Two
<button ng-click="thingToShow.val = 'one';">Switch!</button>
</div>
</div>
// Ctrl
$scope.thingToShow = {val: "one"};

passing variables on jquery

just having some issues with this jQuery thing.
What i'm trying to do is:
i have some audio control buttons that look like this:
<p>Play audio</p>
but there are too many on the page so i'm trying to optimise the code and make a little function that checks for the div id on the button and adds tells the player what track to play.
so i've done this:
<div id="audioControlButtons-1">
<div class="speaker"> </div>
<div class="play"> </div>
<div class="pause"> </div>
</div>
<script>
$(document).ready(function() {
$("[id^=audioControlButtons-] div.play").click(function() {
var id = new Number;
id = $(this).parent().attr('id').replace(/audioControlButtons-/, '');
//alert(id);
player1.loadAudio(id);
return false;
});
});
</script>
my problem is:
the id is not passing to the the player1.loadAudio(id)
if i hardcode player1.loadAudio(1)
it works! but the moment i try to pass the variable to the function it doesn't work...
however if you uncomment the alert(id) thing you will see the id is getting generated...
can someone help?
cheers,
dan
I think I see your problem. The variable id is a string. Try;
player1.loadAudio(parseInt(id));
Yah and the initialise line isn't necessary. Just use;
var id = $(this).parent().attr('id').replace(/audioControlButtons-/, '');
I'm actually kind of confused with your example because you originally have this:
<p>Play audio</p>
but then you don't reference it again. Do you mean that this html:
<div id="audioControlButtons-1">
<div class="speaker"> </div>
<div class="play"> </div>
<div class="pause"> </div>
</div>
Is what you are actually creating? If so, then you can rewrite it like this:
<div class="audio-player">
<div class="speaker"> </div>
<div class="play" data-track="1"> </div>
<div class="pause"> </div>
</div>
Then in your script block:
<script>
$(document).ready(function() {
$(".audio-player > .play").click(function() {
var track = $(this).data('track');
player1.loadAudio(+track);
return false;
});
});
</script>
So a few things are going on here.
I just gave your containing div a class (.audio-player) so that it's much more generic and faster to parse. You don't want to do stuff like [id^=audioControlButtons-] because it is much slower for the javascript to traverse and parse the DOM like that. And if you are going to have multiples of the same element on the page, a class is much more suited for that over IDs.
I added the track number you want to the play button as a data attribute (data-track). Using a data attribute allows you to store arbitrary data on DOM elements you're interested on (ie. .play button here). Then this way, you don't need to this weird DOM traversal with a replace method just to get the track number. This saves on reducing unnecessary JS processing and DOM traversing.
With this in mind now, I use jQuery's .data() method on the current DOM element with "track" as the argument. This will then get the data-track attribute value.
With the new track number, I pass that along into your player1.loadAudio method with a + sign in front. This is a little javascript trick that allows you to convert your value into an actual number if that is what the method requires.
There are at least a couple of other optimizations you can do here - event delegation, not doing everything inside the ready event - but that is beyond the scope of this question. Hell, even my implementation could be a little bit optimized, but again, that would require a little bit more in depth explanation.

Categories

Resources