Patterns or techniques for generalizing objects - javascript

I'm working on a project that requires being able to create, save, and play animated graphics on live streams. So far, I've been able to define whatever graphic types I want to let the user build and display on screen, but these are specific to the kinds of graphics we need to display at work. I want to be able to allow the user to create their own using custom fields.
Here's the object that represents a lower-third graphic right now.
{
_id: 'jdksl;alkdfghjd',
type: 'lowerthird',
style: 'cvhp' //this matches the graphic's style with a show for styling
fields: [
{
name: 'Joe Somebody',
info: 'CVHP Digital Bureau'
},
]
}
So far, I've been able to use the fields array as a way to generalize whatever information I want to display on the graphic when it's displayed on the screen but I'm not understanding how I'll be able to use this pattern when I start figuring out how to let users build custom graphics. I can define and display graphics all day long and, as long as I know what's in the fields everything's golden. If I know I need to display the name of the first field, I just grab graphic.fields[0].name and run with it. But how do I start to tackle user-generated objects whose fields I don't have any information about? Moreover, I don't even know if my data is shaped in a way that makes the most sense for this.
Does anyone know of any good references, tutorials, guides that handle this? Thanks in advance!
edit
The code I use for displaying the generated content is pretty basic but it's specific to the framework I'm using, Svelte. In my case, I'm displaying a list of the created graphics objects:
{#each $graphics as graphic}
<article class="graphic-item">
<header>
<h3>{graphic.type}</h3>
<img src={'/assets/images/' + graphic.style + '.png'} />
</header>
<section class="graphic-item-body">
<ul class="graphic-item-field-list">
{#each graphic.fields as field, index}
<li>
<p class="list-title">{Object.values(field)[0]}</p>
{#if Object.values(field)[1]}
<p class="list-subtitle">{Object.values(field)[1]}</p>
{/if}
{#if Object.values(field)[2]}
<p class="list-subtitle">{Object.values(field)[2]}</p>
{/if}
{#if Object.values(field)[3]}
<p class="list-subtitle">{Object.values(field)[3]}</p>
{/if}
</li>
{/each}
</ul>
</section>
</article>
{/each}

Related

EmberJS template component suddenly not rendering on page

I'm following this Ember tutorial and I've suddenly run into an issue where my rental-listing.hbs template component stops rendering. It started when I began implementing the map service.
I don't understand where this could be happening. I've copied the code from parts of the GitHub repository that I thought were relevant but to no avail.
I have a rental.hbs template that looks like so:
<div class="jumbo">
<div class="right tomster"></div>
<h2>Welcome!</h2>
<p>We hope you find exactly what you're looking for in a place to stay.</p>
{{#link-to "about" class="button"}}
About Us
{{/link-to}}
</div>
{{outlet}}
Which in turn has a template component called rental-listing.hbs:
<article class="listing">
<a
onclick={{action "toggleImageSize"}}
class="image {{if this.isWide "wide"}}"
role="button"
>
<img src={{this.rental.image}} alt="">
<small>View Larger</small>
</a>
<div class="details">
<h3>{{link-to this.rental.title "rentals.show" this.rental class=this.rental.id}}</h3>
<div class="detail owner">
<span>Owner:</span> {{this.rental.owner}}
</div>
<div class="detail type">
<span>Type:</span> {{rental-property-type this.rental.category}} - {{this.rental.category}}
</div>
<div class="detail location">
<span>Location:</span> {{this.rental.city}}
</div>
<div class="detail bedrooms">
<span>Number of bedrooms:</span> {{this.rental.bedrooms}}
</div>
</div>
<LocationMap #location={{this.rental.city}}/>
</article>
The only thing I have added to the above is the line <LocationMap #location={{this.rental.city}}/> but it still doesn't work if I remove it.
The console shows me no errors and I can actually see I am getting the three dummy objects I want from Mirage:
So I'm definitely getting the objects and from what I see I'm doing everything necessary in the templates to render it but they aren't. Should I be looking somewhere else?
Are you able to provide a link to your example? By having each piece of the ember application you mention it would be best to answer definitely. I can give a general answer with strategies for debugging the template.
The conventions behind ember.js make understanding the "whys" frustrating at first and possibly opaque. Ember's handlebars implementation governs how values are populated and accessed within templates using very specific rules. Ember treats templates (handlebars files) differently depending on whether it is for a route or component. Component's have an isolated context and must receive values by explicit passing in or dependency injection. Then, you can use such values in a component's template by accessing those properties with {{this.somePassedInValue}}.
In the super-rentals app, it appears the rental index route invokes the components responsible for displaying the individual units. I found this in app/templates/rentals/index.hbs.
<li><RentalListing #rental={{rentalUnit}} /></li>
The route template iterates over the list of filteredResults. Each of these is the rentalUnit. A good first step would be to use the {{log}} helper to print out that the value of rentalUnit to ensure it is what you expect.
Alternatively, you could try cloning https://github.com/ember-learn/super-rentals and applying the changes you want to make step by step from the master branch. By doing so, you could easily undo a single change to see what caused something to not show up as expected.
<LocationMap #location={{this.rental.city}}/>
to be written as below
<LocationMap #location={{this.rentals.city}}/>
may be typo error.
also repeat this for there place in that template.
Because the model name in the console is rentals not rental

Best practice for displaying Firebase many-to-many relationships in the view (AngularFire)

I have found a lot of examples on how to structure many-to-many relationships in Firebase. Following the most recommended way I've seen to set it up I have some basic posts and tags data in Firebase:
/posts:
-K_GOdSQvCQ2sAcHfo1x
- descpripton: "This is a post..."
- title: "This is a title..."
- tags:
-K_aBTTDKVUovZe3l0lX: true
.....
-K_GFDQjPoSmCJM3YAlB:
- description: "Another post..."
- title: "This title..."
- tags:
-K_aBTTKDhYsnbFv1Tuc: true
......
/tags:
-K_aBTTDKVUovZe3l0lX
- name: "Sport"
- postIds:
-K_GOdSQvCQ2sAcHfo1x: true
.....
-K_aBTTKDhYsnbFv1Tuc:
- name: "Movies"
- postIds:
-K_GFDQjPoSmCJM3YAlB: true
.....
My problem is figuring out how to handle these relationships in my views. I haven't been able to find any tutorials or examples covering it.For example, in the index view I wish to list all posts with their respective tags attached.
So far I've been simply returning all posts and all tags and storing them in separate $scope variables. That's fine but I haven't been able to figure out how to display only the tags relative to each post. I first thought it should be possible trying a nested ng-repeat structure. But it's proving trickier than I expected to get this working.
This is the idea of what I am trying to achieve.
<!-- For each tag in post object iterate tags -->
<div data-ng-repeat="t in posts.tags">
<span data-ng-repeat="tag in tags">
<!-- display only tags here that match with post.tag.id -->
</span>
</div>
I'm thinking that it is perhaps possible using Angular's filter in conjunction with ng-repeat but I've had no luck finding any examples to work from. Maybe what I am trying to do is not possible in the view alone or too cumbersome/ugly. If anyone can give me some pointers on how I might approach it that would be great!
UPDATE
Ok, I have found a way to achieve this but I'm sure it's not optimal. If anyone can inform me on a better approach I'd be grateful.
For example, in the code below I feel that using <h5 ng-if="key === post.$id"> isn't the right way to match the posts to the tags. Maybe there is a standard way of using the boolean values to do this? I'm still a bit new to Firebase/AngularFire so I am eager to learn any emerging design patterns for solving this problem.
Again, the goal is pretty standard. The posts and tags are coming from separate Firebase nodes that have a many-to-many relationship(allowing posts to have many tags and tags to belong to many posts).
In the controller for the index view all posts and all tags are retrieved and saved separately to their own $scope variables. The following view code is how I managed to display the relevant tags inside each post preview.
<li data-ng-repeat="post in posts">
........
<div ng-repeat="tag in tags"> // Iterate tags
<div ng-repeat="(key, value) in tag.postIds"> // Iterate postIds in each tag
// Check tag.postId key against the current post id.
// Should be using booleans some way here instead??
<h5 ng-if="key === post.$id">
<span class="label label-default">
{{tag.name}}
</span>
</h5>
</div>
</div>
</li>
Short answer: denormalize your data.
A bit longer answer: You need to save the data in a way that helps you be efficient when you query it. So for this particular case, you could save the tag's name instead of just true which only shows association.
So instead of
{
posts:
-K_GOdSQvCQ2sAcHfo1x: {
descpripton: "This is a post...",
title: "This is a title...",
tags: {
-K_aBTTDKVUovZe3l0lX: true
}
}
}
You could save it like
{
posts:
-K_GOdSQvCQ2sAcHfo1x: {
descpripton: "This is a post...",
title: "This is a title...",
tags: {
-K_aBTTDKVUovZe3l0lX: "Sport" // <----- Notice the change
}
}
}
Watch this (and others, like this playlist) videos from the official Firebase chanel. Extremely helpful.

JQuery accessing text deep below unique id

I'm trying to make an app that pulls our data from our existing website. As we have no known API, I have decided to use ajax with whateverorigin.org to pull the full HTML from our site, and parse it with jQuery from there.
Unfortunately, much of the data I need lies far below any unique ID's. With $(data.contents).find("#unique").text() I am able to retrieve data of the type:
<div id="unique">
<div>
Text I want
</div>
</div>
However, as the nesting gets deeper, like:
<span id="unique2">
<table>
<tbody>
<tr>
<td>
Text I want
that snippet always returns "".
I have tried chaining the levels together with .join, but that doesn't work either.
Code in context here, around line 40-50. The site I'm trying to access is wmbr.org. The id that works is #now_on_the_air, one of the id's that doesn't is #recent_plays. The log is empty.

Using templating and filtering in AngularJS

I'm pretty new to Angular, and I've run into an issue. I'm hoping that there is an easy way to solve this problem.
Basically, I have a list of Appointments that I retrieve from the server.
$scope.appointments = [{starts_at: "2015-1-1", name: "First"}, {starts_at: "2015-1-1", name: "Last"}, {starts_at: "2015-1-2", name: "Next Day"}];
Now I'd like to show these appointments in a list. I decided that I could use ng-repeat + filters for this, but now I'm stuck.
<ion-slide-box on-slide-changed="slideHasChanged($index)">
<ion-slide>
<div class='box'>
<div class="list list-inset" ng-repeat="appt in appointments | filter:????>
<div class="item" ng-click="openAppointmentModal(appt)">
<span>Appt {{appt.name}}</span>
<span>Starts at {{appt.starts_at}}</span>
</div>
</div>
</div>
</ion-slide>
</ion-slide-box>
I wasn't sure if I could use the built-in filterFilter to do this, so I ended up writing my own filter filterDateFilter, which takes in an array, a property name, and what date you want to filter for. I can then write something like ng-repeat='appt in appointments | filterDate:starts_at:curDate' where curDate is defined by $scope.curDate = new Date() in the controller.
Phew. That works, but only for filtering for whatever $scope.curDate is defined as.
Now, I want to the user to be able to swipe to the previous/next days, and show only the appointments for that day. I assume I'd have to move the <ion-slide> to a template, but I'm not sure where to go from there. What are my next steps?
Sorry for the long post and detailed explanation, but I didn't want to just throw up a question and show no previous effort.
I think that instead of ion-slide, you can use the ionic on-slide-left and on-slide-right directives to call a function you define in your controller which increments or decrements $scope.curDate by 1. This seems a simpler alternative to me than simulating infinite slides.
http://ionicframework.com/docs/api/directive/onSwipeLeft/

One way binding + dynamic binding in AngularJS

I will start by explaining what we are trying to achieve.
We have just jumped on the Angular bandwagon and are building a prototype with it to see what it is capable of.
Currently there is a load of data (grades in this case) on the server and we display that data using Angular.
The following is the code we use:
<ul class="phones">
<li class="list-group-item" onclick="toggleExpandedView(this, true, 500)" ng-repeat="grade in grades | filter:query | orderBy:orderProp">
<span ng-show="grade.comment"><img src="../Content/images/comment.gif"/></span>
<a class="btn btn-primary editButton" style="float: right; position: absolute; right:10px;" ng-href="#/grades/{{grade.gradeId}}">Edit</a>
<div class="heading1"><a ng-href="{{grade.url}}" target="_blank">{{grade.gradeValue}}</a></div>
<div>Provided by {{grade.assessorFirstname}} {{grade.assessorLastname}} on {{grade.dateModifiedFormatted}} </div>
<div class="expandedGrade" onclick="childDivClick(event)" style="display: none" id="grade-{{grade.gradeId}}">
<label>Attachments</label>{{grade.attachmentCount}}
<br />
<span ng-hide="editing" ng-click="editing = true"><b>{{grade.comment || 'No comments yet'}}</b></span>
<form ng-show="editing" ng-submit="editing = false">
<input type="text" ng-model="grade.comment" placeholder="Comment" ng-required />
<br />
<input id="saveChanges" type="submit" class="btn btn-primary" ng-click="saveChanges(this, grade)" text="Save changes" />
</form>
</div>
</li>
</ul>
As you can see we have a parent ul and for each grade in grades we simply display a li and a div that is hidden and when you click on the li we use jQuery to animate and display the hidden div. In the child div we have a comments field which users can update and click save. On save the current object gets fired back to the server however we are concerned about the fact that Angular has to go through all 2000 grades until it finds the one we are updating (due to two way binding) and this means that everything will be really slow and we cannot afford that.
This is what we want to achieve:
1 We want to bind the data one way so that we can display the list of all grades on the screen and as soon as they are all displayed we want to somehow remove the bindings.
2. When users update the comments for a particular grade we then want to dynamically bind that particular grade so that Angular knows exactly which one it has to update without having to go through the whole collection of 2000+ grades.
I have find a tutorial however I am still unsure how to integrate that into my code.
I have also watched this video and I understand the concept behind it but again, I am struggling to write something that actually works ( we have just started using Angular so I am pretty much a newbie)
Could anyone out there point me in the right direction and provide me with some code samples that would solve the issue we are facing? Any advice and help would be greatly appreciated
You could always use a directive
The logic should go like this
use a service to hold your grades
inject the service into your directive
make a copy and just bind the 'read only view' in your directive
you could watch the service for changes and makes updates as needed
in your directive
as far a lazy loading / updating when needed - use a data service
and call the data service for an update whenever the trigger fires
if your trigger needs to come as a push from some other 'web service' consider a technology
like http://socket.io/
I can put together an example if you would like to see how the services and directives should interact

Categories