How to apply Emojis to Angularjs directive list? - javascript

I'm learning Angular JS and currently doing a chat app, I want to apply the Javascript conversion .shortnameToImage(str) offered by Emojione to the list of messages in the chat app on my front end.
This is on my html index the messages display
<ul>
<li ng-repeat="message in messages track by $index">
{{message}}
</li>
</ul>
So, my intention is that everything in the {{message}} gets evaluates so if another user sends :smile: well the smile emoji shows up without involving the back end.
So far I've tried to use a javascript function that that evaluates the user input and makes the conversion to li element but works on the first message.
What's the best approach I can take to resolve this?

The real Angular way would be to create a filter yourself (https://docs.angularjs.org/guide/filter) or use existing https://github.com/globaldev/angular-emoji-filter. And then usage would be as simple as {{message | emoji}}.

Edited to reflect Sergio's comments
Javascript is a good approach for this. You can cycle through all of your li elements with
var array_of_li = document.querySelectorAll("ul.messages li");
You can then convert them with a simple loop.
var array_of_li = document.querySelectorAll("ul.messages li");
for (var i = 0; i < array_of_li.length; i++) {
convert(array_of_li[i]);
}
And here's the conversion code based on the emojione doc :
function convert(li_html) {
var input = li_html.innerHTML;
var output = emojione.shortnameToImage(input);
li_html.innerHTML = output;
}
I've put all of that together in this jsfiddle and it displays a nice emoji smile.

Looking at their docs, it's pretty straightforward and there are no gotchas (if you managed to install it correctly, that is)
http://git.emojione.com/demos/jsshortnametoimage.html
<ul>
<li ng-repeat="message in messages track by $index">
{{ emojione.shortnameToImage(message) }}
</li>
</ul>

Related

How do I iterate an output data from an array in an object

I am trying to create a daily weather app and i'm having issues trying to figure out how to output the data into cards for all seven days. its currently only outputting the last day. I know that its because if am setting it to $("#card__days").html( but im not sure how to add onto the current html.
Is there also any easier way to output this information? I feel like I did way too much for a simple task. Thank you
function updateDaily(data) {
Object.keys(data.daily.data).forEach(function (i) {
// call to find what the day is.
let date = calculateDay(data.daily.data[i].time);
console.log(data.daily.data[i]);
let iteration = i;
let high = data.daily.data[i].temperatureHigh;
let low = data.daily.data[i].temperatureLow;
let feels = data.daily.data[i].apparentTemperature;
let desc = data.daily.data[i].summary;
let icon = data.daily.data[i].icon;
let skycons = new Skycons({ color: "#3e606f" });
$("#card__days").html(`
<div class="card__daily">
<h2 id="daily__date"${iteration}">${date}</h2>
<canvas src="" alt="icon" class="icon" id="daily__icon${iteration}"></canvas>
<div class="degrees">
<h3 id="daily__high${iteration}" class="temp">${high}℉ / ${low}℉</h3>
</div>
<h3 id="daily__desc${iteration}">${desc}</h3>
</div>
`);
skycons.add(
document.getElementById("daily__icon" + i),
icon
);
skycons.play();
});
}
EDIT: Here is what it currently looks like and some data from the API.
Current Visual Output
Some data from Object
If you want to make all seven cards appear, use .append() instead:
$("#card_days").append(/* Your card HTML */);
You only see the last card because in each iteration the for loop overwrites the html with the latest ${iteration} data, instead of creating a new piece of data and a new html element. To fix this:
You could use the $("#card_days").append method, from the other comment in this thread, but personally in a similar situation I used:
$("#card_days").insertAdjacentHTML('beforeend', html) method, it will insert the code you give it as an html parameter just before the closing tag of the element you selected.
As a side note, I only used insertAdjacentHTML because I needed the user to be able to create and delete these html elements, so their amount could not be predefined. In your case, it seems like you know you need exactly 7 elements. If this is the case, I would suggest to stick with html and css, and the only usage of JS would be to update a placeholder text with the newly-fetched data. Hard-coding in this case seems a bit more error-proof :)

Only show unique date values in ng-repeat list

I have a unordered list generated by an ng-repeat. In each list item I have a month header and a blog post.
I only want to show one instance of each month name but I can't work out a nice way of doing this without some really hacky jQuery.
Is there a way I can somehow detect this value in Angular and use an ng-hide to only show the first one of each type?
Maybe something like this could help, providing that your same-month posts are adjacent. If they are not, maybe it's okay to show the date altogether:
plnkr code example
Basically:
<li ng-repeat="post in model.blogPosts">
<span ng-show="model.blogPosts[$index - 1].date !== post.date">{{post.date}}</span>
<br>
<span>{{post.post}}</span>
</li>
Edit:
(Sorry for the default ul li styling, such uglyness)
You should probably modify your data to achieve this. Turn your post list into an object like
$scope.postsByMonth = {
October: [//...october posts],
November: [//...november posts],
//...
};
Then you can do something along these lines
<li ng-repeat-start="month, posts in postsByMonth">month<p>posts[0]</p></li>
<li ng-repeat-end ng-repeat="post in posts.slice(1)"><p>post</p>

AngularJS change <li> element tags based on condition

I have a list in which each list element can have different styles. Simple HTML looks like this:
<li class="active">One</li>
<li>Two</li>
When the user clicks twothen I want the active element to move to that list item. I have tried the following solution.
// In my menu controller
// Determines which link that should be active
$scope.activeLinkID = 0;
// Associative array with link names and paths
$scope.linkArray = {};
// Index 0 = linkName, index 1 = linkPath
$scope.linkArray[0] = ["One", "#/link/one"]
$scope.linkArray[1] = ["Two", "#/link/two"]
[...]
I have tried to display this in my view like this:
<li ng-repeat="(linkIndex, link) in linkArray | orderBy:linkIndex">{{link[0]}}</li>
But I got stuck when trying to add elements into my <li> tag. The condition would be activeLinkID == linkIndex then add class="active".
I'm not sure which is the best way to achive this using AngularJS. What is the best way to do it?
In your controller
$scope.selectedIndex = -1;
$scope.links = [
["One", "#/link/one"],
["Two", "#/link/two"]
];
In your view
<li ng-repeat="link in link"
ng-class="{'active': $parent.selectedIndex == $index}">
<a ng-click="$parent.selectedIndex = $index">{{link[0]}}</a>
</li>
Here's a working demo http://jsbin.com/exafUmuq/2/edit?html,js,output
It seems like you're trying to accomplish something that ui-router was built to solve. You should take some time to learn about it, it will save you lots of headaches.
Great video on ui-router can be found here
https://egghead.io/lessons/angularjs-introduction-ui-router
Try adding a div the ng function inside your div like this
<div> <li ng-repeat="(linkIndex, link) in linkArray | orderBy:linkIndex">{{link[0]}}</li></div>
See if that works. Did for me

JQuery Mobile dynamic listview loses style (data-inset) after updating

I am creating a mobile app (Phonegap/Cordova 1.5.0, JQM 1.1.0) and testing on iOS 5.1. I have a list of items that the user "owns" or wants to own. Throughout the app, the user can edit their list by adding and removing items. Whenever items are added or removed, the list updates, and it is displaying fine, with all of the JQuery CSS intact except the corners are no longer rounded (I'm thinking because data-inset is getting set to "false").
Here is my html for the list-headers:
<div data-role="page" id="profile">
<div data-role="header" data-position="fixed">
<...>
</div><!-- /header -->
<div data-role="content" data-theme="a">
<...>
<ul id="user-wants-list" data-role="listview" data-inset="true" data-theme="d" data-dividertheme="d" >
</ul> <!--/Wants list-->
</br>
<ul id="user-haves-list" data-role="listview" data-inset="true" data-theme="d" data-dividertheme="d" >
</ul> <!--/Has list-->
</br></br>
</div> <!--/content-->
</div> <!--/Profile-->
And here is the Javascript where I remove the old list and dynamically add the new one (the parameter 'haves' is an array of objects):
function displayHaves(haves){
var parent = document.getElementById('user-haves-list');
removeChildrenFromNode(parent);
parent.setAttribute('data-inset','true');
$(parent).listview("refresh");
var listdiv = document.createElement('li');
listdiv.setAttribute('id','user-haves-list-divider');
listdiv.setAttribute('data-role','list-divider');
listdiv.innerHTML = "I Have (" + haves.length + ")";
parent.appendChild(listdiv);
//create dynamic list
for(i=0;i<haves.length;i++){
var sellListing = haves[i].listing;
var userInfo = haves[i].user;
var itemData = haves[i].item;
//create each list item
var listItem = document.createElement('li');
listItem.setAttribute('id','user-haves-list-item-'+i);
parent.appendChild(listItem);
var link = document.createElement('a');
link.setAttribute('id','user-haves-link-' + i);
new FastButton(link, function(listing) {
return function() { displaySellListingPage(listing); }
}(sellListing));
listItem.appendChild(link);
var link = document.getElementById('user-haves-link-' + i);
var pic = document.createElement('img');
pic.setAttribute('src',itemData.pictureURL);
pic.setAttribute('width','80px');
pic.setAttribute('height','100px');
pic.setAttribute('style','padding-left: 10px');
link.appendChild(pic);
var list = document.getElementById('user-haves-list');
$(list).listview("refresh");
}
}
and my function removeChildrenFromNode(parent) is as follows:
function removeChildrenFromNode(node){
while (node.hasChildNodes()){
node.removeChild(node.firstChild);
}
}
So my question is, why does the listview lose the data-inset attribute?
Or, equally valid: is there another way I could/should be achieving corner rounding besides "data-inset='true'"?
Here are things I have tried:
using .trigger("create") on both the listview and the page
adding the listview with explicit styling each time by using $("#page-ID").append(...)
I read another post on StackOverflow that said that JQM creates some inner elements when you create an item (this post had to do with dynamic buttons not being the right size), and that there are some classes (like .ui-btn) that you can access (that may be losing styling when I remove the children from the node?), but I was unable to make any headway in that direction.
Thanks in advance for the help!
I figured out the answer to my question, but not a solution (yet).
$(list).listview('refresh') was getting called on some elements before they had been put on the page, so it was essentially being called on nothing (or another way to think about it is that each list item being appended happens after the refresh call, so it overrides some of the visual styling).
I know the problem has to do with asynchronous loading in javascript. Essentially, the .listview('refresh) executes before the earlier code, which creates the elements but takes longer to execute. I understand the reasoning behind the design, but is there some way to get around this in this case?
I am thinking some conditional that I could set, like:
var doneLoading = false;
//Then when finished set doneLoading to 'true'
if(doneLoading) $(list).listview('refresh');
but if the refresh gets called first, I figure that doneLoading will just evaluate to false and then not execute once the list is actually done loading.
Is there any kind of onComplete callback I can use, or a way to make it happen synchronously?
Try calling listview(refresh) after updating the HTML.

Updating an HTML list using Js

So I have a js game like scrabble. Now when the user makes a new word, I would like the word to be added to a list that is displayed in a div on my page.
The issue is I quite don't understand, how I could keep my old word created and insert a new word with new formatting and everything in a list form.
I know there is a list tag --
<ul>
<li>apple</li>
<li>ball</li>
</ul>
but what I can't really figure out is how do I use java script to enter the word as a new list entry.
I have used js to display the word created by the following syntax
document.getElementById('currentword').innerHTML = word;
where word is the variable that holds the current word created and currentword is the div id. but how do I use this kind of syntax for a list?
Please help!
Thanks
EDIT: I would also like the last entry to the list as the first item on my list. Seems like the list populates itself but the latest entry gets hidden and the list doesn't really auto scroll down as the items are added.
PS: Also incase someone knows how I could replace the tacky scroll bar option generated by CSS to a custom scroll bar. It would be great if you could point me in the correct direction!
Given a list:
<ul id="theList" >
<li>apple</li>
<li>ball</li>
</ul>
you could add an <li> like this (assuming that the variable word contains the word you want to add):
document.getElementById('theList').innerHTML += ('<li>'+word+'</li>');
There are other ways too, but this one is probably the simplest.
I use jQuery for dom manipulation and would recommend the same for you, it adds a lot of readability and tons of neat (x-browser friendly) functionality.
For example... the append api call would do the job if you were using jQuery.
<ul id="words">
<li>Some Word</li>
<li>Another Word</li>
</ul>
$("#words").append("<li>" + yourNewWord + "</li>");
Or with straight javascript...
document.getElementById('words').innerHTML += '<li>' + yourNewWord + '</li>';
EDIT:
I believe in motools the equivalent to .append is .grab
Basic idea:
var li = document.createElement("li");
li.innerHTML = "new text";
document.getElementById("TheULsId").appendChild(li);
<ul>
<li>apple</li>
<li>ball</li>
</ul>
then,
var newListItem = $('<li></li>').html("myNewWord");
$("ul").append(newListItem);
Well to the exact solution of my question, I figured out the rest from mootools docs :)
This fiddle demonstrated most of it.. http://jsfiddle.net/WngSS/1/
As for the scroll bar goes, well to customize ur own scrollbar you just use css effects.

Categories

Resources