Thursday, April 24, 2025

Fighting with *ngFor? Let's talk about error NG9.

Let's talk more about Angular 18.

So you want to iterate through an array in Angular to use repeating sections on your UI.  Right?  Well, Angular supplies a directive called *ngFor, which essentially creates a for loop on your page. 

Let's say you're generating menu items dynamically on your page.  You could hard-code them in the HTML, but if there's any chance the menu items may change in some way, you're asking for trouble.   Besides, even HTML code should be as reusable as we can make it, right?\

Let's create a custom component whose sole purpose in life is to display a menu of hyperlinks. 

Step 1.

 Once you've generated your shiny new component, you'll need to import *ngFor, since it isn't in the Angular core.   Add this line:

import { CommonModule } from '@angular/common';

Be sure to include CommonModule in your imports array as well:

imports: [CommonModule],

So far, so good.  

Step 2.

Now, we need a data source.  Let's create an array that has a few section headers along with the name of the sections on this page we'll be navigating to.

const SECTIONS = [
  {id: 1, name: 'About', url: '#section1'},
  {id: 2, name: 'Projects', url: '#section2'},
  {id: 3, name: 'Experience', url: '#section3'},
  {id: 4, name: 'Education', url: '#section4'},
  {id: 5, name: 'Publications', url: '#section5'},
  {id: 6, name: 'Press', url: '#section6'},
  {id: 7, name: 'Blog', url: '#section7'}
];

Now we need to expose this array to the HTML template.  In the export function, add a line to do that:

export class MenuComponent {
  sections = SECTIONS;
}


Great.  Notice how we can make the variable name different from what it is internally.  You can make it the same if you like, but in this case, I wanted it to be lowercase in order to look cleaner on the template.

Step 3.

Now let's move over to our HTML template.

<html>
 <body>
   <table class="navbar">
     <tr *ngFor="let section of sections">
       <td><a href="{{section.url}}">{{section.name}}</a></td>
     </tr>
   </table>
 </body>
</html>

In this case, I'm going to use a table to display these elements.  Each row will display the data from one item in the array.  As an attribute of tr, we use the *ngFor and set it to the phrase  "let section of sections" where 'sections' is the name of the array we exposed in the component class, and 'section' is what each of the individual items will be referred to.

For each of the columns, we want to display a hyperlink with the data from our section array.   We create a basic link using 'a href' and set the target to the 'url' field from our data array.   The text to be displayed is then set to the 'name' field in the array.  

Now save it, build it and ng serve it!






Wednesday, April 23, 2025

Resolving Angular Error NG8001. Not as obvious as you'd think.

  So I've been working on a little Angular project and ran across an error.  It appears to be a common enough error, but as I went looking for the solution, I discovered that much of the advice you'd get for looking for this solution tends to overthink the issue, and wasn't helping.  Now, I realize that this error is because of a pretty basic problem, but what was strange to me is that I was following an Angular tutorial step by step to ensure I wasn't missing anything, and I still had the problem.

Not All Tutorials Are Created Equal

  There are some really fantastic tutorials out there for just about anything you can think of.  There are also a good number of ones that... aren't fantastic.  The biggest difference seems to be the level of detail, which is a function of how much the author of the tutorial either assumes the reader knows already or just doesn't think of it because it's second nature to them.  It's like if a seasoned Java developer writes a tutorial and neglects to mention the minimum Java version you need to use the 'record' keyword.  They don't consciously think of it when writing a tutorial because it's second nature to them, but a person who actually needs to use the tutorial isn't necessarily aware of it.

  Thus, I found even a simple Angular tutorial to be lacking some very essential information.  Here's what I found on my own.

If you've got a NG8001 error...

  You'll find you have this problem pretty quick if you go to run your Angular application and it won't compile because:

✘ [ERROR] NG8001: 'app-heroes' is not a known element:

1. If 'app-heroes' is an Angular component, then verify that it is included in the '@Component.imports' of this component.

2. If 'app-heroes' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@Component.schemas' of this component to suppress this message. [plugin angular-compiler]

It seems pretty obvious at first glance.  Well, of course, you have to import your component.  But what if the tutorial is a bit vague on exactly how to do it?  Here's how I fixed it.  Yes, I understand this is super basic.  Yes, I understand that a seasoned Angular developer isn't likely to make this mistake.  But you know, we do sometimes forget if we haven't used a particular skill for a while, or if we take a tutorial as being gospel, even when we know better.  So this is for all the folks who are new to Angular, or who aren't new to it but just made one of those goofy Friday afternoon mistakes.

Let's assume our Angular project file structure has its custom components in a folder called 'components.'  Let's further assume that each custom component is in its own folder.  (All of which should be true.)  

Note:  A custom component is what they mean by "Angular component" in the error message output.

Let's say your root component (app.component) needs to import your custom component (in this case, heroes.component).  You've already referenced this component in your root component template, which is what triggered the error.  To import it, you have to do two things, both in the app.component.ts file:

First, you add an import statement to the list of imports at the top of the file:

import { HeroesComponent } from './components/heroes/heroes.component';

Note a couple of things here.  First, you don't need the '.ts' extension for your component.  For one thing, you're referencing the whole component, not just one file in it.  (I know there's a way to override it and make that work, but I'm not aware, off the top of my head, how that benefits you.)  

Also note that we're following the file structure I described earlier.  This is what allows you to organize your project.

The second thing you need to do is add the component to the array of imports in the @Component decorator:

imports: [RouterOutlet, HeroesComponent],

Note that we're using the class name for the component, not the selector.

And that's it.  Your component has been imported.

Again, I know this is a very simple, basic, newbie-type issue, but it struck me as odd that nobody out there seems to be listing it as one possible cause when people are searching for help on the NG8001 error.  

Note that this assumes you're using Angular 17+.

Monday, July 22, 2024

GitHub and SSH. How Do I Make It Work?

 If you have a GitHub repo but haven't used it in a while, or if you're just setting one up, you may have noticed the old username/password approach is not an option anymore when trying to push from your local repo.

My weapon of choice (at least, for Java development) is Eclipse, and I wanted to be able to push/pull and all that good stuff using the UI.  There are a few gotchas to that, so here's how to set up ssh with your GitHub account.

First, you'll want to create your RSA key.  This is straightforward.  Just open your favorite console application and type:

ssh-keygen -t ed25519 -C "youremailaddress@somemailprovider.com"

And go through the questions it prompts you.  You DO want to create a passphrase when it asks you.

Now in your user home folder will be a folder called .ssh.  (It may be hidden.)  Go into that folder and you'll see the public key you just created.  (Hint: It's the file that ends in .pub)  Open that up in a text editor and copy the contents of that file onto your clipboard.  An easier way to do that that ensures you won't accidentally pick up any spaces in your clipboard is the command:

clip < filename.pub

This does the same thing.

Now log into your GitHub account.  On your account page, click the little icon with your picture in the upper right corner and select "Settings."



On the left of the settings page, select "SSH and GPG keys."


Click the "New SSH Key" button.


Give it a title and then copy the contents of your clipboard into the "Key" text area.  Finish up by clicking the "Add SSH Key" button.

As Bon Jovi would say, we're halfway there.


Now we need to configure Eclipse.

Open up Eclipse and select "Preferences" under the "Window" menu.


Under General > Network Connections select "SSH2."


The SSH2 Home field should already be populated, if not, make sure it points to the .ssh folder in your home directory (Or, if you like to be a rebel, point it to whatever folder you put your new RSA key in instead of the default.  I won't judge.)

Hit the "Add Private Key..." button and use it to pick your private RSA key.  That's the file that matches the name of the public key but without the ".pub" extension.

Under the Authentication Methods tab, make sure publickey is checked.


Now, back to the list of Preferences.  Select Version Control (Team) > Git.

Make sure "Store SSH key passphrases in secure store" is checked.  The first time you connect to your GitHub repo it will prompt you for the passphrase you gave it when creating the RSA key.  After that, it will be secured in secure store and won't ask you for it again.



Not done yet...

When you first connect to a GitHub repo you'll have some configuration to do on the connection protocol.  If this is a repo that already exists,  you can get to those settings by:

Right click the project in the Package Explorer window.

 Select Team > Remote > Configure push to upstream...



In the line where it shows the URI, click "Change..."


Under Connection, change the Protocol setting to ssh.  Under Authentication, make the username "git."

I know that isn't your GitHub username.  Trust me.  Put "git" in there anyway.


Now test it!



It isn't very complex, but there are some gotchas.  Follow these steps and you should be good to go.


 


Thursday, July 4, 2024

Things that can't play nice. EACCES when installing Angular

Have you ever had one of those experiences when you try and install something on your system and it really feels like absolutely every. single. step takes a lot more effort and hassle than it ought to?  Before long you're exhausted from fighting your machine, you feel more lost than you did when you started, and now you're wondering what it would take to roll your system back to the point before you started so you don't have all the extra junk on your system from the battle you've been having?

Yeah.

It is often the case that we work with technologies that are constantly changing.  Angular, for example, releases a new version every 6 months.  That usually isn't a big problem if you already have it installed and running.  Then, all you have to do is update.

But what happens when you're setting up a new environment?  When something goes wrong, you head on over to Stack Overflow, Baeldung, or whatever your favorite source of advice is and look for the answer.  Simple enough, we do that all the time.  But what happens when there are a dozen different methods of doing what you want, some of which still work on the latest versions, some don't, and there's always a variety of other approaches that will lead you astray because whoever offers that advice is making certain assumptions about your environment that may not be accurate.

I decided I needed to refresh my Angular skills (among others) so I created a new Ubuntu Linux VM on my machine.  I prefer Linux environments to Windows anyway.

"Well you know, ArcticFox, installing Angular on Windows is very easy.  Just do that!"

"Easy" is not the goal.  The goal is to learn something, exercise skills, and avoid giving Microsoft more data to sell. 

So we take our Linux VM, running Ubuntu 24.04 LTS.  What's our first step?

Step 1

Well, first we need our JavaScript framework, Node.js.  It should be at least version 14.20 when installed on Ubuntu 24.04.

After doing the usual sudo apt-get update to be sure all of your packages are up to date...

Your screen should look like this.  Don't get used to it,
 things will not continue going this smoothly for long.

Great, so all of our packages are up to date so we use apt-get to install nodejs and npm.

sudo apt-get install nodejs

Now, some sources will tell you to use the command "apt-get install nodejs npm."  Do not do that.  npm comes with nodejs anyway so there's no need to specify it, and if this is a fresh install then some of the package dependencies won't yet have been installed and you'll get a nasty error that will have you chasing your tail needlessly.  (Is there ever a time when one does need to chase their tail?)

This is what it looks like without errors.  If yours looked
like this on your first try, then pat yourself on the back.

Now we see if the installation went well.  We can do that by seeing what happens when we run node and npm each with a -v.  This proves that the commands are now in our path and shows us what version we just installed.

node -v
npm -v

Hopefully, your screen looks something like that with no 
"Command not found" errors.

Now, if at some point something went wrong and you're getting an error because of missing dependencies when installing nodejs don't panic.  Just go ahead and install them.  This line of code should cover everything you need:

sudo apt install curl gnupg2 gnupg git wget -y

Some of this stuff is probably already on your system but it won't hurt anything to include them in the command.

If you had dependency errors, yours won't look like this because it will have been 
installing the stuff you were missing.   Hopefully.

And now, we install Angular using the Node Package Manager.  Note that we are not using sudo here, because we're letting the Node Package Manager handle everything.  In fact, it would be a BAD idea to use sudo here.

npm install -g @angular/cli

It is at this point that some people, those who were favored by the Universe, will be able to continue.  The rest of us will  have to deal with this hideous error:


The Pain Train has left the station.

The problem with any "permission denied" error in Linux is that it could mean you don't have permissions, but it could also mean the destination file path doesn't exist.

Now, I know that the output there suggests running the command again as root.  (By using sudo).  Do not do it.  I know it's tempting.  It would probably even work to get past this step, but if you do you're asking for headaches down the road.

So the script failed when it tried to do a mkdir on /usr/lib/node_modules.

So first let's make sure the node_modules folder exists.


There it is!

Ok it's there.  Note also the permissions.  The owner is root, and nobody else gets write permissions.

What, if anything, is already in that folder?

Stuff.  Stuff is what's in that folder.

So that folder was indeed created when we installed npm, but we did that with sudo, remember?  So of course the folder is owned by root.  

No, that doesn't mean rerunning the Angular install with sudo.  Chill.


Now WE have the power.

Ok so now you own the folder.  Let's run that install again.

Chooo choooooooo!

Same error!  Wait... no... not the same.  Now we have a problem where it wants to create a symlink in another folder that it doesn't have permissions on.  Namely, /usr/bin.  Now, I'm not really a fan of taking ownership of that folder.  It can have unexpected side effects, especially if anyone else uses that same machine.  So what we can do is give write permissions just for now without changing the owner.

sudo chmod o=rwx /usr/bin

Now the folder will look like this:

Now everybody can write to it...  Hm...

Now we run the install once again.


And you don't even have to use the wrong argument like I did to test.  Neato!

Once you run the install once more, you should see no more errors.  Now when you enter 

ng --version

You'll get a response with the version of Angular that's installed on your machine.

Now, I'm not a fan of leaving critical Linux folders with wonky permissions so let's put /usr/bin back the way it was and test to be sure we're still good.

Presto!

And now we can even check to see what new stuff we have 



And now the @angular folder being present tells us that all is right with the world.  I'm inclined to leave ownership of the node_modules to myself since it isn't a critical Linux folder and since I am the only one who will ever use this VM, but if you're sharing a machine with others you'll want to be sure that folder is accessible to them as well if they're going to be doing any work with npm, since they may have to install modules there as well.
















Monday, July 19, 2021

Connection refused: Why is my UNIX socket client giving me this?

Language:  C++

Environment: Ubuntu 20

Application:  Creating a UNIX Socket server


If you go out onto the Internet looking for help with this, you'll find oodles and oodles of articles, forum posts, blog posts, tutorials and everything in between explaining how TCP sockets work and how to create them, use them, debug them, take them out to the park and run around with them...

...but UNIX sockets get very little love, and that's not so good when you run into a problem with one.

(The easiest way to tell the difference is to look at the code presented by one of these sites.  Look at the socket() system call.  If the first parameter is AF_INET, you're working with an Internet socket.  If it says PF_UNIX, you're where you want to be.)

A UNIX socket is essentially a special file.  That's it.  That means all the stuff that you could run into when working with files can also impact you when working with UNIX sockets.  The beauty of this is that if you have any experience working with files from your C++ program, then you already have the experience you need to debug problems with your UNIX sockets.

Suppose your "Connection refused" error comes right after a line that looks something like this:

connect(server_,(const struct sockaddr *)&server_addr,sizeof(server_addr))

Inside sockaddr (which is a struct of type sockaddr_un) is a field that holds the path name.  Yes, that means file path.  So what might cause a connection refused?  Well, what sorts of things cause a failure when you try to open a file?  Maybe the file doesn't exist.  Maybe the process doesn't have access privileges on that file.  (See where I'm going with this?)

When the connect() function tries to open that UNIX socket, the socket needs to:

  • Exist.  Don't try to manually create it yourself using mkdir or touch.  That socket gets created when you run a UNIX socket server.  
  • Be a socket.  This is why you don't create it yourself.  When the socket server creates the socket and calls the bind() system call, the socket can now be connected to by a socket client.  Yes, that implies that you have to start your socket server before your client.
  • Be accessible.  Whatever user your process is running as needs to have permissions on that socket in whatever file directory it exists in.  
This is what a socket looks like on the file system when you do ls -l:

srwxrwxr-x  1 arcticfox arcticfox    0 Jul 19 21:13 my_sock

This one is in the /tmp directory, which is a nice, safe, out of the way place.  Notice the first letter for the file type is 's' as opposed to 'd' which it would be if it were a directory.  That's how we know it's a UNIX socket.   

So if you've done everything correctly but your client is refusing to connect, check these three things.


 So it's been a while since I've posted anything here.  It isn't that I died or stopped developing software.  It's that I'm in a radically different field of development and have prettymuch left web development behind for the time being.  

Now I'm working in Artificial Intelligence and robotics.  That is exactly as cool, and as terrifying, as it sounds.

I haven't posted lately because much of what I've been doing over the last few years has either had very little relevance to development in general or it was proprietary stuff that I couldn't share publicly even if there was some use in doing so.  

In my current position though, I get to work with lots of open source and/or non proprietary software as well, and I'll try to share what I learn as I learn it, as before.

Monday, December 18, 2017

Problems with Primefaces Picklists

Primefaces is awesome. JSF is awesome.

Know what isn't awesome? The documentation.

Don't get me wrong... The Primefaces document and the Showcase demo site are very good for introducing the components and the basics on how to use them. The problem is that sometimes they're a little too basic. For example, the picklist component. It says right in the Primefaces PDF that most often, pojos will be used with the picklist, and that it is necessary to implement a Converter to handle it... and that's it. It goes on to show how some facets can be used to make the component look more spiffy, but the developer is left with very little information on what the Converter is for, exactly and how to implement it.

That's why this post exists.

So here's an example that will hopefully help.

<p:picklist converter="#{shipConverter}" itemlabel="#{ship.name}" value="#{backingBean.pickDLM}" var="ship"/>

So here, the converter is just the name we give to our instance of the ShipConverter class, which implements Converter.  itemLabel is the field within one of the contained objects that will be displayed in the picklist windows.  Value is the DualListModel which is defined in the backing bean and serves as the source of data for the picklist.  Var is the reference to each individual item, the same as in a table or tree.

So how does that DualListModel work?

In your backing bean, you'll need your data source for the picklist. 

DualListModel<Ship> pickDLM = null;  //matches the value field on the view
List<Ship> shipSource = DatabaseSourceObject.getShips();
List<Ship> shipTarget = newArrayList<Ship>();

Notice that the source object is a list of Ship objects which will populate the left pane of the picklist.  The target is the right pane, and is initially empty.  If your project needed to pre-populate a few items in the right pane, you would add them to the target object here.  So now we put it all together:

pickDLM = new DualListModel<Ship(shipSource, shipTarget);

So then all you need in your backing bean is the getters and setters for the DualListModel. 

Now for the Converter...

@FacesConverter(value="shipConverter")
@Managedbean(name="shipConverter")
public class ShipConverter implements Converter{

  public ShipConverter(){}//Constructor Stub
  
  //This method provides an implementation for converting the strings in the pickList view back into the objects they represent.
  @Override
  public Object getAsObject(FacesContext context, UIComponent uiComponent, String value){
  pickList pickList = (PickList)uiComponent;
  DualListModel listModel = (DualListModel)pickList.getValue();
  for(Object item : listModel.getSource()){
    Ship ship = (Ship)item;
    if(ship.getName().equals(value)){
      return ship;
    }
  }
}

  //This method provides an implementation for getting the String value of an object in the picklist.
@Override
public String getAsString(FacesContext context, UIComponent uiComponent, Object object){
  String result = ((Ship)object).getName();
  return result;
}
}

That's it.  The idea is to specify exactly how to switch back and forth between the collection objects and their String representations in the picklist.

Enjoy!