I am searching SoundCloud's API and want to be able to add a song to the page once it is clicked from the search results. I am using Plangular and need to also append the tags for that. However, jQuery doesn't seem to like including Angular tags in the append function.
Here is the Search.js
$.ajax({
type: 'POST',
url: '/api/v1/add_song',
data: songParams,
success: function (newSong) {
$('#latest-posts').append(
"<div class='sc-track' plangular='"
+ newSong.url
+ "'><div class='pull-left'<img ng-src='{{track.artwork_url}}'></div> <h3>{{track.user.username}} - {{track.title}}</h3> <button ng-click='playPause()'>Play/Pause</button><progress ng-click='seek($event)' ng-value='currentTime / duration' > {{ currentTime / duration }} </progress> <br> <a ng-href='"
+ newSong.url
+ "'> View on SoundCloud </a>"
+ "</div>"
)
}
})
I am new to Angular, so I'm sure there is a better way to do this. Any help is greatly appreciated!
If you are using Angular, you shouldn't be using jQuery for the ajax calls. I'd suggest you first learn more about the declarative way Angular works, instead of the imperative way jQuery works. Basically you don't modify elements from the controller directly. What you could do is make an array of posts in a controller: $scope.posts. Then you make an ajax call with $http, and in the callback you add the retrieved post to the $scope.posts e.g. $scope.posts.push(response). In your HTML you do something like this:
<body ng-controller="YourController">
<div class="latest-posts">
<div plangular="post.url" class="post" ng-repeat="post in posts">
...
</div>
</div>
</body>
The post in posts will bind to $scope.posts, and by using the ng-repeat the tags (like plangular) get compiled automatically.
In fact, I barely use jQuery in my apps and I can't even remember giving a div an id. I'd suggest you to follow a good tutorial first and check out this: "Thinking in AngularJS" if I have a jQuery background?
This is not the correct way to append Angular's model values.
You can directly access model values like this. Give it try!
$scope[model_name]
Related
I have a drag and drop UI. Its like a bucket list. What I have done is I have seperated the forms and the UI html for easier data manipulation. I have an empty form like this: (Take note that I am using spring form tags "form:")
<form:form method="POST" id="sampleForm" commandName="sampleForm" modelAttribute="sampleForm" class="navbar-form navbar-center">
<table id="formToBeSaved">
</table>
</form:form>
And then I have a script that is triggered whenever my other sortable receives an item. Sample below:
$("#sortable2").sortable({
connectWith : "#sortable2 ul",
scroll: false,
receive: function(event,ui) {
var saveElement = '<tr id="saveRow['+statusCounter+']"><td><form:input type="hidden" '+
'path="sampleFormModel['+statusCounter+']." class="form-control" '+
'id="name['+statusCounter+'].sampleForm" value="'+ someValue +'"></form:input></td></tr>'
console.log(saveElement);
$("#formToBeSaved").append(saveElement);
statusCounter = statusCounter + 1;
console.log(statusCounter);
};
},
Now the problem is, whenever I submit the form thru ajax an error occurs. It seems that the system does not recognize my < form:input > tag (since I am using spring) because I've just assigned it as a string into a variable. Is there a way to fix this? Thanks stackoverflow community!
You are using Spring XML templates, but the web browser can only work with HTML. This works when you are declaring your code in JSP files because Sprint will parse them and transform them to HTML.
So instead of manually adding JSP to the document, you should edit your JSP files in a way they generate the JSP you expect. In this case, you could use <c:forEach> to generate each <tr>. This answer could help you to do that.
If you only have access to the datas required by these <tr> dynamically, I do not know Sprint enough to help you. Maybe you could find some resources on this question.
I am trying get data from server with json and manupulate it to html.This will be really hard to write and really unclear to understand when I scan my code again if I write it on javascript because I will get data and use jquery append to append data to html element and I should add a lot of html inline.For example:
$.getJSON( "json.php", function( json ) {
$.each( json, function( key, data ) {
$('#content').append('<li class="h" id="id5" >+data.type4+</li><a href="www.example.com" ><li class="fg" id="id6" >+data.typ5e+</li></a><a href="www.example.com" ><li class="gfh" id="id7" >+data.type6+</li></a><a href="www.example.com" ><li class="example213" id="id8" >+data.typ7e+</li></a>');
enter code here
Imagine It will be more more big than this and I should write a lot of inline html in javascript and It will be incredible unreadable.Solution is Angular.js ng-repeat beacause I can write noormal html which is easy to read for all developers andd easy to write but I dont want to use angular.js beacuse It is slow,It contain a lot of bytes and I only want to use two of its method (ng-repeat with databinds).How can I achive this?
I found pretty simple way and without any template library.Just write \ tag end of each line ,native,very simple and readable.In my case I have a lot of if else statement,a lot of adding new variables, that why I cant use angular or that kind of thing and I will simply use \ tag just break line.
I have the following code:
<input id="id">
<button data-action="bea" ng-click="Create($('#id1')[0].value);" class="btn">Insert ID</button>
<button data-action="bea" ng-click="Create($('#id2')[0].value);" class="btn">Insert ID</button>
In the JS I have:
$scope.Create = function (id){
if (id === undefined) {
$scope.data = "You must specify an id";
} else {
$scope.data = data;
console.log(data);
});
}
};
When the call gets into the Create function the value of the id is undefined.
If I add the following line at the beginging of the Create function everything works ok:
id = $('#id')[0].value;
If I send a constant value it works:
<button data-action="bea" ng-click="Create('SomeID');" class="btn">Insert ID</button>
Why is this happening and how can I do that without putting the line of value into the method?
Thanks
This is just an extension of comments and other answers, You could achieve this in many ways using angular, one simple example could be:-
<!-- Add a controller -->
<div ng-controller="MainCtrl">
<!-- Give a model binding to your text input -->
<input ng-model="userEntry" type="text"/>
<!-- ng-click pass which ever argument you need to pass, provided it is an expression that can be evaluated against the scope or any constants -->
<button data-action="bea" ng-click="Create(userEntry);" class="btn">Insert ID</button>
<!-- Some simple data binding using interpolation -->
{{data}}
<!-- Just for demo on repeater on a list of items on the scope -->
<div ng-repeat="item in items track by $index">{{item}}</div>
</div>
Example Demo
My 2 cents on the lines of what were originally trying to do:-
Use angular bindings instead of accessing DOM directly for getting the data, it really helps you deal with just the data without worrying about how to access or render it in DOM. If you think you need to access DOM for implementing business logic re-think on the design, if you really need to do it, do it in a directive. Angular is very opinionated on the design and when where you do DOM access.
ng-model
ng-binding
controller
all about ngmodel controller
This is not the way you should do in AngularJS. You should really think in Angular if you want to use AngularJS. Refer this post ("Thinking in AngularJS" if I have a jQuery background?)
All DOM manipulation should be done in Directive. Refer this page that I found really clear.
(http://ng-learn.org/2014/01/Dom-Manipulations/)
My guess is that $ is not bound to the jQuery function when the ng-click value is evaluated, because it is not exposed in the Angular scope.
Solutions to adress this:
expose the jQuery function in scope somewhere, e.g $scope.$ = $; in a controller.
make the Create function parameterless as you suggested, with a var id = $('#id')[0].value; at the beginning
my favorite : avoid using jQuery. If you put some data in the #id element, there's probably a more natural and AngularJS-idiomatic way of retrieving it than querying the DOM (e.g an Angular service).
In particular, if the element you're targeting is an <input> element, then use the ngModel directive to link the value to a $scopeproperty that will be accessible in the controller :
<input ng-model="inputData"/>
The JavaScript you are trying to pass as a parameter of the create function is not available in the scope of the Create function.
Try to target the element a different way.
Does that help?
This is a very short example, but I was wondering if there is a way of using an xml or html file with html markup instead of including it in the javascript like I do below.
I know there are template libraries out there, but I really just want to do something simple and not involve any libraries other than jQuery.
var description = this.name;
if description == 'full') {
return "<div><textarea cols='50' rows='50'>" + this.value + "</textarea></div>";
} else {
return "<div><textarea cols='50' rows='15'>" + this.value + "</textarea></div>";
};
Thanks
In general, without a template engine you have three options:
a) Adding the template directly into your markup as script tag
<script type="text/template" data-template="stats">
<div id="content">
...
</div>
</script>
The html code inside the script tag could be accessed with the following code:
$("script[data-template=" + templateName + "]").html()
The big benefit of this approach is that you are not making another http request.
b) Putting the template in external file and load it via ajax.
$.ajax({
url: "test.html"
}).done(function(html) {
...
});
c) Doing the things like you already did.
If you use AJAX to call a file, you can use the result of the file, which could be XML or nested HTML, etc etc.
I define a hidden div on my markup - then give it a generic ID, then in javascript I use the jQuery.clone() method to make a clone of that markup, and in the markup I define the template macro values that can then be injected with the real data using .replace..
HTML:
<div id="mytemplate">
Name: {0}
</div>
JS/jQuery:
var clone = $('#mytemplate').clone();
Then perform the replacements on the clone object and simply append to the DOM where desired!
So let's say you display a list of divs that each represent a list item with certain properties (for an example a todo list):
<div class="list">
<div class="items" id="item1">
<div class="itemtitle">Some title</div>
<div class="icon"><img src="1.jpg"></div>
<div class="footer1" />
</div>
.
.
.
<div class="items" id="itemN">
<div class="itemtitle">Some other title</div>
<div class="icon"><img src="2.jpg"></div>
<div class="footer4" />
</div>
</div>
Now each item has three properties (title, a specific icon, and a custom footer). All these properties can be changed via javascript (say clicking on one cycles through the options).
Now everytime something is changed i want to save these changes to the server (and no, i don't want to store the whole html code block (that way i can't sort by the properties later, also it's ugly ;) ). What would be the most elegant and effective way to do this ? (I'm using jQuery if that helps...)
Thanks a bunch !
As long as you have a unique id for each block, you could push each change on blur of that element.
A user changes .itemTitle in #item4, you know the id is 4. So you can use an ajax post, send the item id, the item type (title), and the updated value. Then, on the server side (php, for example), you can do a simple mysql (i'm assuming) update.
Does that make sense? I can show actual code if need be.
If you want to transmit all the changes back to the server in one go, then naturally you need to put them into some kind of <input> element. <input type="hidden"> is the most obvious choice. If you go that route, you can either use an onsubmit handler on your form to update your hidden inputs from the text in the document, or you can update the hidden inputs in realtime as you update the document itself.
As far as how to structure the inputs, that's a harder question because there are several ways to do it and the best way to decide between them, it seems to me, is what's easiest to parse in your server-side framework.
You could create a whole bunch of hidden inputs with name="itemtitle" and a bunch with name="icon" etc, as long as your server-side framework knows how to interpret the resulting form post data as a list-of-values for itemtitle and for icon.
You could create hidden inputs with name="itemtitle1" etc.
Or you could just use one fixed hidden input and populate it with the entire list encoded in some form, such as JSON, if your server-side framework has an easy method for parsing JSON. Then you'd use javascript either in onsubmit or on every change to update the hidden input to consist of [{itemtitle="whatever", icon="whatever, ...}, {itemtitle="..."}] and parse that out as a JSON list on the server side.
Another choice would be to not use hidden inputs at all, but actual textboxes in the document itself. With styling, it's possible to make a textbox look un-editable. If you did that, then your list structure would post back all by itself when it's part of a form post.
One thing you can try is to collect the information into a JavaScript object literal, which essentially like a hashtable/dictionary structure, but you can nest structures inside. It's not a fixed structure, and doesn't require you to have hidden elements in your DOM -- you can have this completely separated from your DOM.
You can then take advantage of JSON notation for transferring this information to your server via a POST. Using Douglas Crockford's JSON2.js library allows you to serialize and de-serialize this structure to/from the object literal notation. And, there's lots of support for JSON on the server side.
So for your example, you could do something like this in jQuery (I extended your markup a little just to have a valid working example):
<div class="list">
<div class="items" id="item1">
<div class="itemtitle">Some title</div>
<div class="icon"><img src="1.jpg"></div>
<div class="footer1">blah</div>
</div>
<div class="items" id="item2">Stuff</div>
<div class="items" id="item3">Stuff2</div>
<div class="items" id="item4">
<div class="itemtitle">Some other title</div>
<div class="icon"><img src="2.jpg"></div>
<div class="footer4">boo</div>
</div>
</div>
(I'm assuming that your DIV ids are sequentially numbered -- item1, item2, item3, etc.)
and the JavaScript...
var theData = {};
$(document).ready(function() {
$(".items").click(function() {
theData["title"] = $(this).find(".itemtitle").text();
theData["icon"] = $(this).find(".icon img").attr("src");
theData["footer"] = $(this).find(".footer" + ($(this).index()+1)).text();
alert(JSON.stringify(theData));
});
});
(I'm assuming the footer data can be selected based on the sequentially numbered DIV id.)
Now that your changed data is in the theData object literal variable, you can send it to your server/service via a jQuery $.ajax call:
$.ajax({
url: "/ajax_json_echo/",
data: theData, //just pass the literal to your server...most can handle it
type: "POST",
dataType: "json",
success: function(data) { alert(JSON.stringify(data)); }, //output it readable form
error: function(x, t, m) { alert("Error: " + t + " :: " + m); }
});
You can check out a fiddle I put together that demos this.
I hope this helps!